package com.yungu.swift.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.yungu.swift.assets.driver.model.dto.*;
import com.yungu.swift.assets.driver.model.vo.DriverVo;
import com.yungu.swift.assets.driver.service.*;
import com.yungu.swift.assets.passenger.model.dto.PassengerCouponDto;
import com.yungu.swift.assets.passenger.model.dto.PassengerDto;
import com.yungu.swift.assets.passenger.model.vo.PassengerVo;
import com.yungu.swift.assets.passenger.service.PassengerCouponService;
import com.yungu.swift.assets.passenger.service.PassengerService;
import com.yungu.swift.autoconfig.lock.RedisLock;
import com.yungu.swift.autoconfig.redis.RedisCacheService;
import com.yungu.swift.autoconfig.redis.RedisStringCacheService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.common.model.dto.CommonTagDto;
import com.yungu.swift.common.service.CommonTagService;
import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.constants.OrderConstant;
import com.yungu.swift.lbs.model.Coordinate;
import com.yungu.swift.lbs.model.DriverLocation;
import com.yungu.swift.lbs.model.DriverPoint;
import com.yungu.swift.lbs.model.dto.LatLngDto;
import com.yungu.swift.lbs.model.vo.DrivingNearestVo;
import com.yungu.swift.lbs.service.DistanceService;
import com.yungu.swift.lbs.service.LocationService;
import com.yungu.swift.order.config.ApplicationConfig;
import com.yungu.swift.order.consts.Constants;
import com.yungu.swift.order.dao.OrderCallHistoryMapper;
import com.yungu.swift.order.dao.OrderDetailMapper;
import com.yungu.swift.order.dao.OrderFareMapper;
import com.yungu.swift.order.dao.OrderMapper;
import com.yungu.swift.order.helper.OrderAssignHelper;
import com.yungu.swift.order.helper.OrderHelper;
import com.yungu.swift.order.helper.PassengerHelper;
import com.yungu.swift.order.model.dto.OrderCallHistoryDto;
import com.yungu.swift.order.model.dto.OrderDetailDto;
import com.yungu.swift.order.model.dto.OrderDto;
import com.yungu.swift.order.model.dto.OrderFareDto;
import com.yungu.swift.order.model.param.*;
import com.yungu.swift.order.model.vo.*;
import com.yungu.swift.order.processor.CommissionProcessor;
import com.yungu.swift.order.processor.CrosstownOrderProcessor;
import com.yungu.swift.order.service.*;
import com.yungu.swift.order.thread.driver.status.DriverStatusCycleRunnable;
import com.yungu.swift.order.thread.order.OrderHandleThreadPoolUtil;
import com.yungu.swift.order.utils.CommonUtils;
import com.yungu.swift.order.utils.PolylineUtils;
import com.yungu.swift.order.utils.SendMessageUtils;
import com.yungu.swift.order.utils.ThreadExecutorUtils;
import com.yungu.swift.socket.push.model.PushContent;
import com.yungu.swift.socket.push.service.PushService;
import com.yungu.swift.system.finance.model.dto.FinanceJoinRefundDto;
import com.yungu.swift.system.finance.model.dto.FinancePrepayDto;
import com.yungu.swift.system.finance.service.FinancePrepayService;
import com.yungu.swift.system.sys.model.dto.SysBusinessOperateLogDto;
import com.yungu.swift.system.sys.model.dto.SysWayCalculationDto;
import com.yungu.swift.system.sys.model.dto.SysWayDto;
import com.yungu.swift.system.sys.model.param.AdminDepartLimitPageParam;
import com.yungu.swift.system.sys.model.vo.WayfenceInfoVo;
import com.yungu.swift.system.sys.service.*;
import com.yungu.swift.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.yungu.swift.constants.OrderConstant.*;
import static com.yungu.swift.order.helper.OrderHelper.*;
import static com.yungu.swift.order.helper.OrderPushHelper.*;
import static com.yungu.swift.order.service.OrderAssignService.ASSIGN_DRIVER_LOCK;
import static com.yungu.swift.order.service.impl.OrderAssignServiceImpl.ASSIGN_ORDER_LOCK;
import static com.yungu.swift.socket.push.model.PushContent.*;

/**
 * 跨城 / 小件订单业务
 *
 * @author : cuixiuyin
 * @date : 2019/12/5
 */
@Slf4j
@Service
public class OrderJoinServiceImpl implements OrderJoinService {

    @Autowired
    private RedisLock redisLock;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderFareMapper orderFareMapper;
    @Autowired
    private OrderCallHistoryMapper orderCallHistoryMapper;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderFareService orderFareService;
    @Autowired
    private OrderRiskControlService orderRiskControlService;
    @Autowired
    private OrderSecretNoService orderSecretNoService;
    @Autowired
    private RefundService refundService;
    @Autowired
    private CommissionProcessor commissionProcessor;
    @Autowired
    private CrosstownOrderProcessor crosstownOrderProcessor;
    @Autowired
    private RedisCacheService redisCacheService;
    @Autowired
    private RedisStringCacheService redisStringCacheService;
    @Reference
    private CommonTagService commonTagService;
    @Reference
    private PushService pushService;
    @Reference
    private DriverService driverService;
    @Reference
    private CarModelValuationService carModelValuationService;
    @Reference
    private PassengerService passengerService;
    @Reference
    private PassengerCouponService passengerCouponService;
    @Reference
    private DriverStatusCycleService driverStatusCycleService;
    @Reference
    private CarService carService;
    @Reference
    private CarModelService carModelService;
    @Reference
    private LocationService locationService;
    @Reference
    private DistanceService distanceService;
    @Reference
    private FinancePrepayService financePrepayService;
    @Reference
    private SysWayService sysWayService;
    @Reference
    private SysCityService sysCityService;
    @Reference
    private SysWayFenceService sysWayFenceService;
    @Reference
    private SysWayCalculationService sysWayCalculationService;
    @Reference
    private SysAccountPassengerService sysAccountPassengerService;
    @Reference
    private SysBusinessOperateLogService sysBusinessOperateLogService;
    @Reference
    private SysDepartLimitService sysDepartLimitService;
    @Reference
    private OrderAssignService orderAssignService;

    @Override
    public ResponseData<List<OrderDto>> getCompleteOrderByDate(Map<String, Object> params) {
        return ResponseData.buildSuccessResponse(orderMapper.getCompleteOrderByDate(params));
    }

    @Override
    public ResponseData<JsonOrderDetailVo> startJoinOrder(String orderUuid) {
        OrderDto order = findOrder(orderUuid);
        if (null == order) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取订单信息失败");
        }
        //校验
        if (order.getCloseStatus() == ORDER_CLOSE_STATUS_CLOSED) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：订单已被关闭，详细请查看订单详情");
        }
        if (order.getJoinStatus() != ORDER_JOIN_STATUS_WAIT_START) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：订单状态异常");
        }
        //更新拼车（主&子）订单状态
        orderMapper.updateStatusByJoinOrderRelatedUuid(order.getMainOrderUuid(), ORDER_JOIN_STATUS_STARTED);
        //更新所有关联订单出发时间
        Map<String, Object> build = MapUtils.build(4);
        build.put("mainOrderUuid", order.getMainOrderUuid());
        build.put("driDepartTime", new Date());
        orderFareMapper.batchUpdateRelatedByMainOrderUuid(build);
        //获取司机信息
        DriverDto driver = driverService.get(order.getActualDriverUuid()).getData();
        if (driver == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取司机信息异常");
        }
        //获取司机车辆信息
        CarDto car = carService.get(driver.getCarUuid()).getData();
        if (car == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取司机车辆信息异常");
        }
        //获取关联订单
        String mainOrderUuid = order.getMainOrderUuid();
        Map<String, Object> params = new HashMap();
        params.put("orderUuid", mainOrderUuid);
        params.put("byUnCompleted", 1);
        List<OrderDto> orders = orderMapper.findRelatedByOrderUuid(params);
        if (null == orders || orders.isEmpty()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取关联订单失败或订单状态异常");
        }
        //推送
        List<String> targetOrderUuids = new ArrayList<>();
        Map<String, String> uuidToPasUuidMap = new HashMap<>();
        OrderDto mainOrderDto = null;
        for (OrderDto o : orders) {
            targetOrderUuids.add(o.getUuid());
            uuidToPasUuidMap.put(o.getUuid(), o.getPassengerUuid());
            if (o.getTypeMain().equals(ORDER_TYPE_MAIN)) {
                mainOrderDto = o;
            }
        }
        //移除主单
        orders.remove(mainOrderDto);
        List<OrderDetailDto> details = orderDetailMapper.findByOrders(MapUtils.build("orders", orders));
        if (CollectionUtils.isEmpty(details)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取关联订单详情失败");
        }
        for (OrderDetailDto detailDto : details) {
            /*消息推送*/
            String content;
            //小件订单
            if (detailDto.getParcelInfoName() != null) {
                content = "行程开始：您寄件时间：" + DateUtils.format(detailDto.getDeparTime()) + "的订单，司机已经出发来取件，请提前准备好货件！";
                //发送收件码给收件人
                SendMessageUtils.generalSend(detailDto.getReceiverMobile(), "您有一个由" + detailDto.getSenderName() +
                        "寄出的货件，收件码：【" + detailDto.getReceiptCode() + "】,请在货件送达时,告知司机确认，并检查货件信息无误", order.getAppid());
            } else {
                content = "行程开始：您于出发时间：" + DateUtils.format(detailDto.getDeparTime()) + "的订单，司机已经出发来接您，请准时到达上车地点！";
            }
            pushListOrder2Pas(Arrays.asList(uuidToPasUuidMap.get(detailDto.getOrderUuid())), detailDto.getOrderUuid(), detailDto.getAppid(),
                    "行程开始", content, ORDER_JOIN_PAS_ORDER_STARTED);
        }
        // 记录状态周期
        ThreadExecutorUtils.execute(new DriverStatusCycleRunnable(
                driverStatusCycleService,
                locationService,
                order.getAppid(),
                order.getActualDriverUuid(), orderUuid,
                order.getCarUuid(),
                DriverStatusCycleDto.ACTION_RIDE));
        return orderService.getOrderDetail(orderUuid, null);
    }


    @Override
    public ResponseData<JsonOrderDetailVo> completeJoinOrder(String orderUuid) {
        OrderDto orderDto = findOrder(orderUuid);
        if (null == orderDto) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取订单信息失败");
        }
        Map<String, Object> objectMap = new HashMap(4);
        objectMap.put("orderUuid", orderDto.getMainOrderUuid());
        objectMap.put("byUnCompleted", 1);
        List<OrderDto> orders = orderMapper.findRelatedByOrderUuid(objectMap);
        if (null == orders || orders.isEmpty()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取关联订单失败或订单状态异常");
        }
        //存在跨城小件时  校验司机是否全部已确认收货码
        List<JsonOrderDetailVo> orderDetailVoList = orderMapper.getReceiptCode(MapUtils.build("orderUuid", orderDto.getMainOrderUuid()));
        //还有未确认收货的跨城小件订单
        if (orderDetailVoList != null && orderDetailVoList.size() > 0) {
            for (JsonOrderDetailVo jsonOrderDetailVo : orderDetailVoList) {
                if (StringUtils.isEmpty(jsonOrderDetailVo.getConfirmReceiptCode())) {
                    ResponseData.buildErrorResponse(10010, "未全部确认收货码", orderDetailVoList);
                }
            }
        }
        Double mainOrderTotalFare = 0d;//总价
        Double mainOrderActualFare = 0d;//实际支付价格
        Double mainOrderCouponFare = 0d;//实际抵扣金额
        for (OrderDto order : orders) {
            //子订单需更新司机流水和平台抽成
            if (ORDER_TYPE_MAIN.equals(order.getTypeMain())) {
                continue;
            }
            if (order.getCloseStatus() == ORDER_CLOSE_STATUS_CLOSED) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：订单已被关闭，详细请查看订单详情");
            }
            if (order.getJoinStatus() != ORDER_JOIN_STATUS_STARTED) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：订单状态异常");
            }
            //抽成、流水、司机收入 —— 非收现类型订单 现金支付不记流水、不抽成
            if (order.getPayType() != PAY_TYPE_CASH) {
                PayVo payVo = null;
                //第三方支付、获取预支付补充
                if (order.getPayType() == PAY_TYPE_TENPAY || order.getPayType() == PAY_TYPE_ALIPAY) {
                    Map<String, Object> build = MapUtils.build();
                    build.put("orderUuid", order.getUuid());
                    build.put("status", FinancePrepayDto.STATUS_PAID);
                    FinancePrepayDto financePrepayDto = financePrepayService.get(build).getData();
                    if (financePrepayDto == null) {
                        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取关联子订单预支付信息失败");
                    }
                    try {
                        payVo = JsonUtils.readValue(financePrepayDto.getParams(), PayVo.class);
                    } catch (IOException e) {
                        log.error("OrderService completeJoinOrder JsonUtils readValue error.param:{}", financePrepayDto.getParams(), e);
                    }
                } else {//余额支付、非第三方（微信、支付宝）支付
                    payVo = new PayVo(PAY_PURPOSE_CHARGE_FARE, CommonConstant.PASSENGER, order.getPayType(),
                            order.getPassengerUuid(), order.getUuid(), null, null,
                            order.getAppid(), null, null);
                    payVo.setOrderDto(order);
                    //获取乘客uuid
                    PassengerVo passengerVo = new PassengerVo();
                    passengerVo.setUuid(order.getPassengerUuid());
                    payVo.setPassengerVo(passengerVo);
                    //获取订单价格
                    OrderFareDto orderFareDto = orderFareService.get(MapUtils.build("orderUuid", payVo.getOrderUuid())).getData();
                    if (orderFareDto == null) {
                        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到订单价格信息");
                    }
                    payVo.setOrderFareDto(orderFareDto);
                    //获取司机
                    DriverVo driverVo = driverService.selInfo(order.getActualDriverUuid()).getData();
                    if (driverVo == null) {
                        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到司机信息");
                    }
                    payVo.setDriverVo(driverVo);
                }
                //计算抽成
                commissionProcessor.process(payVo);
            }
            /* 更新乘客&司机成单量 */
            //乘客成单量+1
            passengerService.incrPasOrderCountByUuid(order.getPassengerUuid());
            //司机成单量+1 --MainOrderUuid为空说明是虚拟主订单(其他为主订单的子订单)，虚拟主订单不能累计到司机成单量里
            if (StringUtils.isNotEmpty(order.getMainOrderUuid()) && order.getMainOrderUuid().equals(orderDto.getMainOrderUuid())) {
                driverService.incrDriOrderCountByUuid(order.getActualDriverUuid());
            }
            //获取订单详情
            List<OrderDetailDto> details = orderDetailMapper.list(MapUtils.build("orderUuid", order.getUuid()));
            if (null == details || details.isEmpty()) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单异常：获取详情失败");
            }
            OrderDetailDto detail = details.get(0);
            //获取订单价格
            List<OrderFareDto> fares = orderFareMapper.list(MapUtils.build("orderUuid", order.getUuid()));
            if (null == fares || fares.isEmpty()) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单异常：获取价格失败");
            }
            OrderFareDto fare = fares.get(0);
            //主订单价格
            mainOrderTotalFare += ParamUtil.defaultIfNull(fare.getTotalFare(), 0d);
            mainOrderActualFare += ParamUtil.defaultIfNull(fare.getActualFare(), 0d);
            mainOrderCouponFare += ParamUtil.defaultIfNull(fare.getCouponFare(), 0d);

            //乘客：预约成功
            String content;
            //订单为跨城小件时，定义通知文本
            if (CommonConstant.ORDER_TYPE_JOIN_PARCEL == order.getTypeJoin()) {
                content = "您寄件时间：" + DateUtils.format(detail.getDeparTime()) + " 取件地：" + detail.getOriginAddress() + " 收件地：" + detail.getDestAddress() + " 的订单已经送达，如有意见请及时反馈，期待您的评价。";
            } else {
                content = "您于出发时间：" + DateUtils.format(detail.getDeparTime()) + " 出发地：" + detail.getOriginAddress() + " 目的地：" + detail.getDestAddress() + " 的订单已结束行程，如有意见请及时反馈，期待您的评价。";
            }
            pushListOrder2Pas(Arrays.asList(order.getPassengerUuid()), orderDto.getUuid(), orderDto.getAppid(),
                    "达到目的地", content, ORDER_JOIN_PAS_ORDER_COMPLETE);
        }

        //更新拼车（主&子）订单状态
        orderMapper.updateStatusByJoinOrderRelatedUuid(orderDto.getMainOrderUuid(), ORDER_JOIN_STATUS_COMPLETED);
        //更新所有关联订单完成（到达）时间
        Map<String, Object> build = MapUtils.build();
        build.put("mainOrderUuid", orderDto.getMainOrderUuid());
        build.put("arriveTime", new Date());
        orderFareMapper.batchUpdateRelatedByMainOrderUuid(build);
        //更新主订单价格表
        List<OrderFareDto> list = orderFareMapper.list(MapUtils.build("orderUuid", orderDto.getMainOrderUuid()));
        if (CollectionUtils.isEmpty(list)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单信息异常");
        }
        OrderFareDto mainOrderFare = list.get(0);
        long departTime = mainOrderFare.getDriDepartTime().getTime();
        long arriveTime = mainOrderFare.getArriveTime().getTime();
        long tripDuration = (arriveTime - departTime) / (1000 * 60);
        mainOrderFare.setTripDuration((int) tripDuration);
        mainOrderFare.setTotalFare(mainOrderTotalFare);
        mainOrderFare.setActualFare(mainOrderActualFare);
        mainOrderFare.setCouponFare(mainOrderCouponFare);
        orderFareMapper.edit(mainOrderFare);
        // 记录状态周期
        ThreadExecutorUtils.execute(new
                DriverStatusCycleRunnable(
                driverStatusCycleService,
                locationService,
                orderDto.getAppid(),
                orderDto.getActualDriverUuid(), orderUuid,
                orderDto.getCarUuid(),
                DriverStatusCycleDto.ACTION_SERVICE_OVER));
        //返回订单详情
        return orderService.getOrderDetail(orderUuid, null);
    }


    @Override
    public ResponseData<PageList<JsonOrderDetailVo>> joinPageList(ApiJoinListParam demandParam) {
        //进行中的订单列表
        Map<String, Object> objToMap = MapUtils.convertObjToMap(demandParam);
        objToMap.put("closeStatus", ORDER_CLOSE_STATUS_NORMAL);
        return ResponseData.buildSuccessResponse(orderMapper.joinPageList(objToMap, new PageBounds(demandParam.getNowPage(),
                demandParam.getPageSize())));
    }


    @Override
    public ResponseData<Boolean> closeJoinOrder(JoinOrderParam joinOrderParam) {
        OrderDto orderDto = findOrder(joinOrderParam.getOrderUuid());
        if (null == orderDto) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "查询不到订单信息");
        }
        //判断订单状态
        if (orderDto.getJoinStatus() >= ORDER_JOIN_STATUS_COMPLETED) {
            return ResponseData.buildErrorResponse(0, "订单已完成，无法关闭!！");
        }
        String mainOrderUuid = orderDto.getMainOrderUuid();
        //关闭订单与司机出发互斥操作
        if (StringUtils.isNotEmpty(mainOrderUuid)) {
            ResponseData lockRsd = crosstownOrderProcessor.handleLock(mainOrderUuid);
            if (!lockRsd.isSuccess()) {
                return lockRsd;
            }
        }
        //是否小件订单
        boolean isParcelOrder = (orderDto.getTypeModule() != null && orderDto.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL);
        //是否支付
        boolean isPaid = false;
        if (orderDto.getPayStatus() != null && Constants.ORDER_PAY_STATUS_PAYED == orderDto.getPayStatus()) {
            isPaid = true;
        }
        OrderDetailDto orderDetailDto = findOrderDetail(joinOrderParam.getOrderUuid());
        if (null != orderDetailDto) {
            //是否立即退款
            boolean isRebates = false;
            boolean isRefund = false;
            //预约中（已支付）不是乘客取消
            if (ORDER_JOIN_STATUS_SUBING == orderDto.getJoinStatus() && !joinOrderParam.getCloseType().equals(
                    Constants.ORDER_CANCEL_SUB_STATUS_PASSENGER)) {
                isRefund = true;
            }
            //是否改派
            boolean isChangeAssign = Constants.ORDER_CANCEL_SUB_STATUS_ASSIGNED.equals(joinOrderParam.getCloseType());
            //改派的情况 不作退款处理
            if (isChangeAssign) {
                isRefund = false;
            }
            //已退款的情况下 不作退款处理
            if (orderDto.getPayStatus() != null && orderDto.getPayStatus() == Constants.ORDER_PAY_STATUS_REFUNDED) {
                isRefund = false;
            }
            // 预约成功（待安排）
            if (orderDto.getJoinStatus() >= ORDER_JOIN_STATUS_SUB_OK && joinOrderParam.getCloseType().equals(
                    Constants.ORDER_CANCEL_SUB_STATUS_PASSENGER)) {
                //乘客主动取消 且司机已出发的跨城小件订单 需要扣除部分取消费
                if (isParcelOrder && orderDto.getJoinStatus() == ORDER_JOIN_STATUS_WAIT_START) {
                    isRebates = true;
                }
            }
            orderDetailDto.setCloseReason(joinOrderParam.getCloseReason());
            orderDetailDto.setCloseTime(new Date());
            orderDto.setCloseStatus(ORDER_CLOSE_STATUS_CLOSED);
            orderDto.setCloseType(joinOrderParam.getCloseType());
            //优惠卷抵扣支付 0元
            if (null != orderDto.getPayType() && orderDto.getPayType().equals(PAY_TYPE_COUPON)) {
                //设置为退款成功状态
                orderDto.setPayStatus(Constants.ORDER_PAY_STATUS_REFUNDED);
            }
            //退款处理
            if (isRefund || isRebates || isPaid) {
                RefundParam refundParam = new RefundParam();
                refundParam.setOrderUuid(orderDto.getUuid());
                refundParam.setPayFare(0.0);
                refundParam.setRemark("预约关闭，全额退款。");
                if (!isRefund) {
                    refundParam.setRemark("预约关闭，退款扣除取消费。");
                    //部分退款 获取取消费
                    Map<String, Object> paraMap = new HashMap<>();
                    paraMap.put("wayUuid", orderDto.getWayUuid());
                    paraMap.put("carModelUuid", orderDto.getCarModelUuid());
                    ResponseData<SysWayCalculationDto> cancelFeeRsd = sysWayCalculationService.findOne(paraMap);
                    if (cancelFeeRsd.isSuccess() && cancelFeeRsd.getData() != null) {
                        refundParam.setPayFare(cancelFeeRsd.getData().getParcelCancelFee());
                    }
                }
                ResponseData<Integer> refund = refundService.refund(refundParam);
                if (!refund.isSuccess()) {
                    log.error("退款处理异常：" + refund.getMsg());
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, refund.getMsg());
                }
                orderDto.setPayStatus(refund.getData() == FinanceJoinRefundDto.STATUS_SUCCESS ? Constants.ORDER_PAY_STATUS_REFUNDED : Constants.ORDER_PAY_STATUS_REFUNDDING);
            }
            //更新订单
            //非改派的订单 更新订单
            if (!isChangeAssign) {
                orderDto = saveOrUpdate(orderDto);
                orderDetailService.saveOrUpdate(orderDetailDto);
            }
            //长链接推送
            //乘客消息
            sendPasCancalMsg(orderDto, orderDetailDto, joinOrderParam.getCloseType(), isParcelOrder);
            //司机消息
            sendDriCancelMsg(orderDto, orderDetailDto, joinOrderParam.getCloseType(), isParcelOrder);

            //处理改派信息
            crosstownOrderProcessor.handleChangeAssignMainOrder(orderDto, orderDetailDto, isParcelOrder);

            passengerCouponService.refundCoupon(joinOrderParam.getOrderUuid());
            //解绑隐私号
            orderSecretNoService.unbind(joinOrderParam.getOrderUuid());
            return ResponseData.buildSuccessResponse("操作成功", Boolean.TRUE);
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败");
    }

    private void sendDriCancelMsg(OrderDto orderDto, OrderDetailDto orderDetailDto, String closeType, boolean isParcelOrder) {
        StringBuilder driverMsg = new StringBuilder();
        if (orderDto.getSource() == OrderConstant.ORDER_SOURCE_SCAN_CODE) {
            driverMsg.append("您有一个扫码订单已被取消！");
        }
        // 预约成功（待安排）
        if (orderDto.getJoinStatus() >= ORDER_JOIN_STATUS_SUB_OK) {
            String title = "订单关闭通知";
            String deparTime = DateUtils.format(orderDetailDto.getDeparTime());
            //后台关闭
            if (closeType.equals(Constants.ORDER_CANCEL_SUB_STATUS_ADMIN)) {
                title = "您有一个订单已被后台关闭";
                driverMsg.append("您的订单被后台关闭；")
                        .append(isParcelOrder ? "您寄件时间：" + deparTime + ";" : "您于出发时间：" + deparTime + ";")
                        .append("从").append(orderDetailDto.getOriginAddress())
                        .append("到").append(orderDetailDto.getDestAddress())
                        .append("的订单被后台取消，如有疑问请联系客服：").append(ApplicationConfig.SERVER_CONFIG.getSystem().getJoinServiceTel())
                        .append("。");
            }
            //乘客主动取消
            if (closeType.equals(Constants.ORDER_CANCEL_SUB_STATUS_PASSENGER)) {
                title = "您有一个订单已被乘客取消";
                driverMsg.append("您的订单被用户取消；");
            }
            //跨城小件文本
            if (isParcelOrder) {
                driverMsg.append("寄件人手机：").append(orderDetailDto.getSenderMobile()).append(";")
                        .append("从").append(orderDetailDto.getOriginCity() + orderDetailDto.getOriginAddress())
                        .append("到").append(orderDetailDto.getDestCity() + orderDetailDto.getDestAddress())
                        .append("出发时间：").append(deparTime).append(";")
                        .append("留言：").append(StringUtils.isEmpty(orderDetailDto.getRemark()) ? "无" : orderDetailDto.getRemark()).append("。");
            } else {
                driverMsg.append("乘客手机：").append(orderDetailDto.getActualPasMob()).append(";")
                        .append("从").append(orderDetailDto.getOriginCity() + orderDetailDto.getOriginAddress())
                        .append("到").append(orderDetailDto.getDestCity() + orderDetailDto.getDestAddress())
                        .append("出发时间：").append(deparTime).append(";")
                        .append("用车人数：").append(orderDetailDto.getActualPasNum()).append(";")
                        .append("留言：").append(StringUtils.isEmpty(orderDetailDto.getRemark()) ? "无" : orderDetailDto.getRemark()).append("。");
            }
            if (null != orderDto.getActualDriverUuid()) {
                DriverDto driverDto = driverService.get(orderDto.getActualDriverUuid()).getData();
                if (null != driverDto) {
                    pushOrder2Dri(driverDto.getUuid(), orderDto.getUuid(), orderDto.getAppid(), title, driverMsg.toString(), ORDER_JOIN_CLOSE_ORDER);
                    SendMessageUtils.closeJoinOrder(driverDto.getMobile(), driverMsg.toString(), orderDto.getAppid());
                }
            }
        }
    }

    private void sendPasCancalMsg(OrderDto orderDto, OrderDetailDto orderDetailDto, String closeType, boolean isParcelOrder) {
        StringBuilder passengerMsg = new StringBuilder();
        String title = "订单关闭通知";
        String deparTime = DateUtils.format(orderDetailDto.getDeparTime());
        Date payTime = orderDto.getPayTime();
        //待支付，不是乘客取消
        if (payTime == null && !closeType.equals(Constants.ORDER_CANCEL_SUB_STATUS_PASSENGER)) {
            passengerMsg.append(isParcelOrder ?
                    "很抱歉，您寄件时间：" + deparTime + "的订单已关闭，欢迎再次使用。" :
                    "很抱歉，您于出发时间：" + deparTime + "的订单已关闭，欢迎再次乘坐。");
        }
        //已支付，不是乘客取消
        if (payTime != null && !closeType.equals(Constants.ORDER_CANCEL_SUB_STATUS_PASSENGER)) {
            passengerMsg.append(isParcelOrder ?
                    "很抱歉，您寄件时间：" + deparTime + "的订单已关闭，系统将全额退款，请注意查收！您可以修改订单信息再次预约。" :
                    "很抱歉，您于出发时间：" + deparTime + "的订单已关闭，系统将全额退款，请注意查收！您可以修改订单信息再次预约。");
        }
        if (StringUtils.isBlank(passengerMsg.toString())) {
            return;
        }
        PassengerDto passenger = passengerService.get(orderDto.getPassengerUuid()).getData();
        if (passenger != null) {
            pushOrder2Pas(passenger.getUuid(), orderDto.getUuid(), orderDto.getAppid(), title, passengerMsg.toString(), ORDER_JOIN_CLOSE_ORDER);
        }
        if (passenger != null && payTime != null) {
            SendMessageUtils.closeJoinOrder(passenger.getMobile(), passengerMsg.toString(), orderDto.getAppid());
        }
    }

    @Override
    public ResponseData<Boolean> subscribeJoinOrder(String orderUuid, String userUuid) {
        ResponseData<JsonOrderDetailVo> getOrderDetail = orderService.getOrderDetail(orderUuid, null);
        if (!getOrderDetail.isSuccess() || getOrderDetail.getData() == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：获取订单信息失败");
        }
        JsonOrderDetailVo order = getOrderDetail.getData();
        //业务状态判断
        if (order.getJoinStatus() != ORDER_JOIN_STATUS_SUBING) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：非预约中订单无法确认预约");
        }
        //关闭状态判断
        if (order.getCloseStatus() == ORDER_CLOSE_STATUS_CLOSED) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作失败：订单已关闭");
        }
        /*订单状态更新*/
        orderMapper.updateChildJoinOrderStatus(orderUuid, ORDER_JOIN_STATUS_SUB_OK);
        //确认预约时间、确认人
        OrderDetailDto orderDetailDto = new OrderDetailDto();
        orderDetailDto.setOrderUuid(orderUuid);
        orderDetailDto.setConfirmTime(new Date());
        orderDetailDto.setConfirmUser(userUuid);
        orderDetailMapper.updateByOrderUuid(orderDetailDto);
        //消息推送 - 乘客：预约成功
        List<String> targetUuids = Arrays.asList(order.getPassenger().getUuid());
        String content;
        if (order.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL) {
            content = "恭喜！您的寄件订单，我们已确认预约成功，司机将尽快联系您取件，请您耐心等待。";
        } else {
            content = "恭喜！您的拼车订单，我们已确认预约成功，司机将尽快联系您接驾，请您耐心等待。";
        }
        pushListOrder2Pas(targetUuids, order.getUuid(), order.getAppid(), "订单预约成功提醒", content, ORDER_JOIN_PAS_SUB_SUCCESS);
        //预约单短信推送
        if (order.getTypeTime() == CommonConstant.TYPE_TIME_APPIONT) {
            SendMessageUtils.generalSend(order.getActualPasMob(), content, order.getAppid());
        }
        if (order.getTypeTime() == CommonConstant.TYPE_TIME_REAL_TIME) {
            //实时单预约成功时，检查长连接是否存在，若不存在，则补充短信发送
            if (!pushService.getChannel(targetUuids.get(0)).isSuccess()) {
                SendMessageUtils.generalSend(order.getActualPasMob(), content, order.getAppid());
            }
        }
        return ResponseData.buildSuccessResponse("预约成功！订单状态已更新", Boolean.TRUE);
    }

    @Override
    public ResponseData<Boolean> closeJoinOrder(String appid) {
        StringBuilder orderUuids = new StringBuilder();
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("joinStatus", ORDER_JOIN_STATUS_INIT);
        List<JsonOrderDetailVo> orderDetails = orderMapper.queryJoinByStatusTime(params);
        if (CollectionUtils.isNotEmpty(orderDetails)) {
            for (JsonOrderDetailVo orderDetail : orderDetails) {
                //是否超时
                if ((System.currentTimeMillis() - orderDetail.getCreateOn().getTime()) / 1000 >= 900) {
                    log.info("(定时关闭)未支付订单ID={}", orderDetail.getUuid());
                    orderUuids.append(orderDetail.getUuid()).append(",");
                }
            }
        }
        if (orderDetails != null && orderDetails.size() > 0) {
            for (JsonOrderDetailVo orderDetail : orderDetails) {
                if (null != orderDetail.getPayTime()) {
                    if ((System.currentTimeMillis() - orderDetail.getPayTime().getTime()) / 1000 >= 1800) {
                        log.info("(定时关闭)未安排订单ID={}", orderDetail.getUuid());
                        orderUuids.append(orderDetail.getUuid()).append(",");
                        String msgContent = "您的订单因暂无司机指派，系统已为您自动取消，给您带来不便，请您谅解，欢迎下次继续使用";
                        SendMessageUtils.generalSend(orderDetail.getActualPasMob(), msgContent, appid);
                    }
                }
            }
        }
        if (orderUuids.length() > 0) {
            orderMapper.autoCloseCrosstownOrder(orderUuids.toString());
        }

        return ResponseData.buildSuccessResponse(Boolean.TRUE);
    }

    @Override
    public ResponseData<Boolean> deparOrderPushMsg(String appid) {
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("joinStatus", ORDER_JOIN_STATUS_WAIT_START);
        List<JsonOrderDetailVo> orderDetails = orderMapper.queryJoinByDeparOrder(params);
        for (JsonOrderDetailVo orderDetail : orderDetails) {
            fillOrderInfo(orderDetail);
            //半小时提醒一次
            if ((orderDetail.getDeparTime().getTime() - System.currentTimeMillis()) / 1000 >= 1800) {
                OrderDetailDto orderDetailDto = findOrderDetail(orderDetail.getUuid());
                DriverDto driverDto = driverService.get(orderDetail.getActualDriverUuid()).getData();
                if (null != orderDetailDto && null != driverDto) {
                    //出发时间
                    StringBuilder driverMsg = new StringBuilder();
                    driverMsg.append("预约时间很近了，")
                            .append("从").append(orderDetailDto.getOriginCity() + orderDetailDto.getOriginDetailAddress())
                            .append("到").append(orderDetailDto.getDestCity() + orderDetailDto.getDestDetailAddress())
                            .append("出发时间：").append(DateUtils.format(orderDetailDto.getDeparTime())).append(";")
                            .append("用车人数：").append(orderDetailDto.getActualPasNum()).append(";")
                            .append("请准时出发去接乘客！");
                    pushOrder2Dri(driverDto.getUuid(), orderDetailDto.getOrderUuid(), orderDetailDto.getAppid(),
                            "时间提示", driverMsg.toString(), ORDER_JOIN_ORDER_TIME);
                    //短信推送
                    SendMessageUtils.generalSend(driverDto.getMobile(), driverMsg.toString(), appid);
                }
            }
            params.put("joinStatus", ORDER_JOIN_STATUS_STARTED);
            orderDetails = orderMapper.queryJoinByDeparOrder(params);
            for (JsonOrderDetailVo jsonOrderDetailVo : orderDetails) {
                fillOrderInfo(jsonOrderDetailVo);
                //提醒一次
                Date time = jsonOrderDetailVo.getDeparTime();
                if (time != null && (time.getTime() - System.currentTimeMillis()) / 1000 >= 600) {
                    //消息提醒预留
                    OrderDetailDto orderDetailDto = findOrderDetail(jsonOrderDetailVo.getUuid());
                    PassengerDto passengerDto = passengerService.get(jsonOrderDetailVo.getPassengerUuid()).getData();
                    if (null != orderDetailDto && null != passengerDto) {
                        StringBuilder passengerMsg = new StringBuilder();
                        passengerMsg.append("出发时间近了！您预约的订单：")
                                .append("出发时间：").append(DateUtils.format(orderDetailDto.getDeparTime())).append(";")
                                .append("从").append(orderDetailDto.getOriginCity() + orderDetailDto.getOriginDetailAddress())
                                .append("到").append(orderDetailDto.getDestCity() + orderDetailDto.getDestDetailAddress())
                                .append("快到出发时间了，请您尽快前往上车地点准备上车。");
                        pushOrder2Pas(passengerDto.getUuid(), orderDetailDto.getOrderUuid(), orderDetailDto.getAppid(),
                                "时间提示", passengerMsg.toString(), ORDER_JOIN_ORDER_TIME);
                        //短信推送
                        SendMessageUtils.generalSend(passengerDto.getMobile(), passengerMsg.toString(), appid);
                    }
                }
            }
        }
        return ResponseData.buildSuccessResponse("操作成功", Boolean.TRUE);
    }

    @Override
    public ResponseData<Map<String, Object>> getInfoRelatedOrder(String uuid) {
        OrderDto orderDto = orderMapper.selectForMainChild(uuid);
        if (null == orderDto) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取关联订单失败：订单不存在");
        }
        Map<String, Object> result = new HashMap(16);
        List<JsonOrderDetailVo> jsonOrderDetailVos = new ArrayList<>();
        JsonOrderDetailVo main = null;
        List<JsonOrderDetailVo> children = new ArrayList<>();

        List<String> uuids = new ArrayList<>();
        //该订单为主订单
        if (ORDER_TYPE_MAIN.equals(orderDto.getTypeMain())) {
            //查询关联子订单UUID
            uuids = orderMapper.getRelatedUuids(orderDto.getUuid());
        }
        //未派单的子订单
        if (!ORDER_TYPE_MAIN.equals(orderDto.getTypeMain())) {
            if (StringUtils.isEmpty(orderDto.getMainOrderUuid())) {
                ResponseData<JsonOrderDetailVo> odRS = orderService.getOrderDetail(uuid, null);
                if (!odRS.isSuccess()) {
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取主订单详情失败");
                }
                jsonOrderDetailVos.add(odRS.getData());
            } else {
                //查询关联父&子订单
                uuids = orderMapper.getRelatedUuids(orderDto.getMainOrderUuid());
            }
        }
        if (null != uuids && !uuids.isEmpty()) {
            ResponseData<List<JsonOrderDetailVo>> batchRS = getBatchOrderDetail(uuids);
            if (!batchRS.isSuccess()) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取子订单详情失败");
            }
            jsonOrderDetailVos.addAll(batchRS.getData());
        }
        if (CollectionUtils.isNotEmpty(jsonOrderDetailVos)) {
            for (JsonOrderDetailVo jsonOrderDetailVo : jsonOrderDetailVos) {
                assignOrderDetailVo(jsonOrderDetailVo);
                if (ORDER_TYPE_MAIN.equals(jsonOrderDetailVo.getTypeMain())) {
                    main = jsonOrderDetailVo;
                } else {
                    children.add(jsonOrderDetailVo);
                }
            }
            result.put("main", main);
            result.put("children", children);
            return ResponseData.buildSuccessResponse("获取成功", result);
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取失败");
    }

    /**
     * 批量获取订单关联的全部详情
     */
    private ResponseData<List<JsonOrderDetailVo>> getBatchOrderDetail(List<String> uuids) {
        // 检索订单信息
        Map<String, Object> map = MapUtils.build();
        map.put("batchQuery", 1);
        map.put("uuids", uuids);
        List<JsonOrderDetailVo> jsonOrderDetailVos = orderMapper.listOrderDetail(map);
        if (CollectionUtils.isNotEmpty(jsonOrderDetailVos)) {
            for (JsonOrderDetailVo jsonOrderDetailVo : jsonOrderDetailVos) {
                assignOrderDetailVo(jsonOrderDetailVo);
            }
        }
        return ResponseData.buildSuccessResponse("获取成功", jsonOrderDetailVos);
    }

    private void assignOrderDetailVo(JsonOrderDetailVo jsonOrderDetailVo) {
        fillOrderInfo(jsonOrderDetailVo);
        String uuid = jsonOrderDetailVo.getUuid();
        Date date = new Date();
        //发单正序
        jsonOrderDetailVo.setCountdown(date.getTime() - jsonOrderDetailVo.getCreateOn().getTime());
        // 如果是预约订单，且行程已确定
        if (jsonOrderDetailVo.getTypeTime().compareTo(CommonConstant.TYPE_TIME_APPIONT) == 0
                && ORDER_STATUS_CONFIRM.compareTo(jsonOrderDetailVo.getSubStatus()) == 0) {
            jsonOrderDetailVo.setCountdown(jsonOrderDetailVo.getDeparTime().getTime() - date.getTime());
        }
        //增加是否超过24小时
        jsonOrderDetailVo.setOverTime(0);
        if (jsonOrderDetailVo.getDeparTime() != null && DateUtils.compareByDay(date, jsonOrderDetailVo.getDeparTime(), 1)) {
            jsonOrderDetailVo.setOverTime(1);
        }
        // 如果订单有确定司机的情况下，做以下判断
        if (jsonOrderDetailVo.getDriver() != null && !StringUtils.isEmpty(jsonOrderDetailVo.getDriver().getUuid())) {
            // （预约单）司机是否可以出发去接乘客
            // 当该订单是最近一条预约订单，且距离出发时间1小时内时才可以
            Map<String, Object> srhMap = new HashMap<>();
            srhMap.put("actualDriverUuid", jsonOrderDetailVo.getDriver().getUuid());
            srhMap.put("typeTime", CommonConstant.TYPE_TIME_APPIONT);
            // 检索司机所有进行中预约订单
            List<JsonOrderListVo> listOrderDoing = orderMapper.queryOrderDoing(srhMap);
            // 默认值：不可以出发去接乘客
            jsonOrderDetailVo.setCanPickUp(0);
            // 如果存在进行中订单
            if (listOrderDoing != null && listOrderDoing.size() > 0) {
                // 该订单是最近一条预约订单
                if (listOrderDoing.get(0) != null && uuid.equals(listOrderDoing.get(0).getUuid())) {
                    // 距离出发时间1小时内
                    if (jsonOrderDetailVo.getDeparTime().getTime() - date.getTime() <= 60 * 60 * 1000) {
                        // 可以出发去接乘客
                        jsonOrderDetailVo.setCanPickUp(1);
                    }
                }
            }
            // 司机是否可以催促乘客付款
            // 当乘客未付款超过10分钟可按
            // 默认值：不可以催促乘客付款
            jsonOrderDetailVo.setCanHurryPay(0);
            if (ORDER_MAIN_STATUS_DONE.compareTo(jsonOrderDetailVo.getMainStatus()) == 0) {
                Map<String, Object> fareMap = MapUtils.build(2);
                fareMap.put("orderUuid", uuid);
                OrderFareDto fareDto = orderFareService.get(fareMap).getData();
                // 当乘客未付款超过10分钟可按
                if (fareDto != null && fareDto.getArriveTime() != null
                        && (date.getTime() - fareDto.getArriveTime().getTime() > 10 * 60 * 1000)) {
                    jsonOrderDetailVo.setCanHurryPay(1);
                }
            }
        }
        //播报详情
        jsonOrderDetailVo.setReport(buildReportInfo(jsonOrderDetailVo));
        //更改司机图像地址
        jsonOrderDetailVo.setDriver(jsonOrderDetailVo.getDriver());
        //更改乘客图像地址
        PassengerVo passengerVo = jsonOrderDetailVo.getPassenger();
        if (StringUtils.isNotNull(passengerVo)) {
            if (StringUtils.isNotNull(passengerVo.getFace())) {
                if (StringUtils.isNotEmpty(jsonOrderDetailVo.getActualPasNam())) {
                    passengerVo.setNickname(jsonOrderDetailVo.getActualPasNam());
                }
                if (StringUtils.isNotEmpty(jsonOrderDetailVo.getActualPasMob())) {
                    passengerVo.setMobile(jsonOrderDetailVo.getActualPasMob());
                }
                jsonOrderDetailVo.setPassenger(passengerVo);
            }
        } else {
            PassengerVo newVo = new PassengerVo();
            newVo.setMobile(jsonOrderDetailVo.getActualPasMob());
            jsonOrderDetailVo.setPassenger(newVo);
        }

        //已完成订单计算实付金额 —— 补充加入跨城最优优惠券预设[跨城类型&待支付&未关闭]
        if (jsonOrderDetailVo.getMainStatus().intValue() == ORDER_MAIN_STATUS_DONE || (jsonOrderDetailVo.getTypeModule() == CommonConstant.TYPE_TIME_APPIONT && jsonOrderDetailVo.getJoinStatus() == ORDER_JOIN_STATUS_INIT && jsonOrderDetailVo.getCloseStatus() == ORDER_CLOSE_STATUS_NORMAL)) {
            //计算实付金额(已计算过调整费)
//            BigDecimal actualFare = BigDecimal.valueOf(jsonOrderDetailVo.getTotalFare()).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal actualFare = BigDecimal.valueOf(jsonOrderDetailVo.getTotalFare()).setScale(2, BigDecimal.ROUND_HALF_UP);
            jsonOrderDetailVo.setActualFare(actualFare.doubleValue());
            //获取支付时订单的优惠券价格
            if (!isOrderCanceled(jsonOrderDetailVo.getSubStatus())) {
                PassengerCouponDto couponDto = passengerCouponService.findMinCoupon(jsonOrderDetailVo.getPassenger().getUuid(),
                        jsonOrderDetailVo.getTypeTrip(), jsonOrderDetailVo.getTotalFare()).getData();
                if (couponDto != null) {
                    jsonOrderDetailVo.setCouponUuid(couponDto.getUuid());
                    jsonOrderDetailVo.setCouponFare(couponDto.getMoney());
                    //计算优惠劵抵扣金额
//                    BigDecimal couponMoney = BigDecimal.valueOf(jsonOrderDetailVo.getCouponFare()).setScale(1, BigDecimal.ROUND_HALF_UP);
                    BigDecimal couponMoney = BigDecimal.valueOf(jsonOrderDetailVo.getCouponFare()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    jsonOrderDetailVo.setCouponFare(couponMoney.compareTo(actualFare) == 1 ? actualFare.doubleValue() : couponDto.getMoney());
                    //计算实付
//                    actualFare = actualFare.subtract(BigDecimal.valueOf(jsonOrderDetailVo.getCouponFare())).setScale(1, BigDecimal.ROUND_HALF_UP);
                    actualFare = actualFare.subtract(BigDecimal.valueOf(jsonOrderDetailVo.getCouponFare())).setScale(2, BigDecimal.ROUND_HALF_UP);
                    jsonOrderDetailVo.setActualFare(actualFare.compareTo(BigDecimal.ZERO) == 1 ? actualFare.doubleValue() : 0D);
                }
            }
        }
        //日租半日租拼接订单标题
        if (CommonConstant.TYPE_TIME_DAILY_RENTAL == jsonOrderDetailVo.getTypeTime() || CommonConstant.TYPE_TIME_HALF_DAILY_RENTAL == jsonOrderDetailVo.getTypeTime()) {
            CarModelValuationDto carValuationDto = carModelValuationService.get(MapUtils.build("uuid", jsonOrderDetailVo.getCarModelValuationUuid())).getData();
            if (carValuationDto != null) {
                jsonOrderDetailVo.setTitle("包车" + carValuationDto.getStartDuration() / 60 + "小时");
            }
        }
        if (jsonOrderDetailVo.getDriver() != null && jsonOrderDetailVo.getDriver().getPlateNum() == null) {
            jsonOrderDetailVo.getDriver().setPlateNum("");
        }
        if (jsonOrderDetailVo.getDriver() != null && jsonOrderDetailVo.getDriver().getCarColor() == null) {
            jsonOrderDetailVo.getDriver().setCarColor("");
        }
        if (jsonOrderDetailVo.getDriver() != null && jsonOrderDetailVo.getDriver().getBrandName() == null) {
            jsonOrderDetailVo.getDriver().setBrandName("");
        }
        if (null != jsonOrderDetailVo.getDriver()) {
            try {
                String valueTemp = AESUtils.decryptAES(jsonOrderDetailVo.getDriver().getName(), AESUtils.DEFAULT_KEY);
                if (StringUtils.isNotBlank(valueTemp)) {
                    jsonOrderDetailVo.getDriver().setName(valueTemp);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //过滤拼车
        if (jsonOrderDetailVo.getTypeModule() != CommonConstant.BUSINESS_TYPE_POOL) {
            String originAddressTemp = CommonUtils.getCounty(jsonOrderDetailVo.getOriginDetailAddress());
            if (StringUtils.isNotBlank(originAddressTemp)) {
                originAddressTemp = "（" + originAddressTemp + "）" + jsonOrderDetailVo.getOriginAddress();
                jsonOrderDetailVo.setOriginAddress(originAddressTemp);
            }
            String destAddressTemp = CommonUtils.getCounty(jsonOrderDetailVo.getDestDetailAddress());
            if (StringUtils.isNotBlank(destAddressTemp)) {
                destAddressTemp = "（" + destAddressTemp + "）" + jsonOrderDetailVo.getDestAddress();
                jsonOrderDetailVo.setDestAddress(destAddressTemp);
            }
        }
    }

    @Override
    public ResponseData<OrderCallHistoryDto> recvJoinOrderCall(String phoneNumber, String appid) {
        //保存通话记录
        OrderCallHistoryDto dto = new OrderCallHistoryDto();
        dto.setPhoneNumber(phoneNumber);
        dto.setCreateOn(new Date());
        dto.setStatus(Constants.ORDER_CALL_UNDISPOSE);
        dto.setUuid(StringUtils.buildUUID());
        orderCallHistoryMapper.add(dto);
        // 发送ws消息
        Map<String, Object> data = MapUtils.build();
        data.put("uuid", dto.getUuid());
        data.put("phoneNumber", phoneNumber);
        data.put("createOn", DateUtils.format(dto.getCreateOn()));
        data.put("source", ORDER_SOURCE_PHONE);
        PushContent pushContentByAdmin = newInstance4Admin(appid, NEW_JOIN_ORDER_CALL, data);
        pushService.sendMessageByAdmin(pushContentByAdmin);
        return ResponseData.buildSuccessResponse("通话记录保存成功", dto);
    }

    @Override
    public ResponseData<Map<String, Object>> createCrosstownOrder(JoinOrderParam joinOrderParam) {
        //获取乘客的信息
        PassengerDto passengerDto = getPassengerInfo(joinOrderParam);
        joinOrderParam.setPassengerDto(passengerDto);
        joinOrderParam.setPassengerMobile(passengerDto.getMobile());

        //获取路线
        SysWayDto sysWayDto = getWayInfo(joinOrderParam);
        if (sysWayDto == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取线路失败");
        }
        Date nowDate = new Date();
        //出发时间设置
        log.info("前端传过来的出发时间：{}", joinOrderParam.getDeparTime());
        if (joinOrderParam.getDeparTime() == null) {
            joinOrderParam.setDeparTime(nowDate);
        } else if (joinOrderParam.getDeparTime().before(nowDate)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "出发时间不能小于当前时间");
        }
        //判断订单时效性，当订单出发时间小于等于当前时间30分钟 则为即】实时单 否则为预约单
        Integer typeTime = (joinOrderParam.getDeparTime().getTime() - System.currentTimeMillis()) / (1000 * 60) <= 30 ? CommonConstant.TYPE_TIME_REAL_TIME : CommonConstant.TYPE_TIME_APPIONT;
        joinOrderParam.setTypeTime(typeTime);

        //下单前业务校验
        ResponseData checkRsd = crosstownOrderLogicCheck(joinOrderParam, sysWayDto);
        //校验未通过
        if (!checkRsd.isSuccess()) {
            log.info("下单校验未通过:{}", checkRsd.getMsg());
            return checkRsd;
        }

        //初始化跨城订单
        OrderDto orderDto = new OrderDto();
        OrderDetailDto orderDetailDto = new OrderDetailDto();
        OrderFareDto orderFareDto = new OrderFareDto();
        //创建订单信息
        initOrderInfo(joinOrderParam, sysWayDto, orderDto, orderDetailDto, orderFareDto);
        //保存订单
        try {

            orderMapper.add(orderDto);
            orderDetailMapper.add(orderDetailDto);
            orderFareMapper.add(orderFareDto);
        } catch (Exception e) {
            log.error("下单失败：系统异常！", e);
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "下单失败：系统异常！");
        }
        // 电话订单
        if (OrderConstant.ORDER_SOURCE_PHONE == joinOrderParam.getOrderSource()) {
            //更新通话记录状态及关联订单UUID
            List<OrderCallHistoryDto> list = orderCallHistoryMapper.list(MapUtils.build("uuid", joinOrderParam.getCallUuid()));
            if (CollectionUtils.isEmpty(list)) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作异常：获取通话记录失败！");
            }
            OrderCallHistoryDto orderCallHistoryDto = list.get(0);
            if (null != orderCallHistoryDto.getOrderUuid()) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "操作异常：通话已处理！");
            }
            orderCallHistoryDto.setStatus(Constants.ORDER_CALL_DISPOSED);
            orderCallHistoryDto.setDisposedOn(new Date());
            orderCallHistoryDto.setDisposedBy(joinOrderParam.getUserUuid());
            orderCallHistoryMapper.edit(orderCallHistoryDto);
        }
        Integer orderSource = joinOrderParam.getOrderSource();
        // 后台下单短信推送
        if (OrderConstant.ORDER_SOURCE_ADMIN == orderSource || OrderConstant.ORDER_SOURCE_PHONE == orderSource) {
            log.info("下单短信推送 >>> 后台下单:{}推送至乘客：{}", orderDetailDto.getOrderUuid(), orderDetailDto.getActualPasMob());
            SendMessageUtils.joinOrderConfirm2Pas(orderDetailDto.getDeparTime(), orderDetailDto.getActualPasMob(), orderDto.getAppid());
        } else if (orderSource == OrderConstant.ORDER_SOURCE_SCAN_CODE) {
            //扫码下单模式 直接派单给司机
            CrosstownAssignOrderParam crosstownAssignOrderParam = new CrosstownAssignOrderParam();
            crosstownAssignOrderParam.setCurrentOrderUuid(orderDto.getUuid());
            crosstownAssignOrderParam.setTargetDriverUuid(joinOrderParam.getDriverUuid());
            ResponseData assignResult = orderAssignService.doScanOrderAssign(crosstownAssignOrderParam);
            //派单失败时 回滚数据
            if (!assignResult.isSuccess()) {
                deleteOrderInfo(orderDto, orderDetailDto, orderFareDto);
                return assignResult;
            }
        } else {
            // 管理后台推送
            Map<String, Object> data = MapUtils.build();
            data.put("orderUuid", orderDto.getUuid());
            data.put("source", orderDto.getSource());
            PushContent pushContentByAdmin = PushContent.newInstance4Admin(orderDto.getAppid(), PushContent.NEW_JOIN_ORDER_TIP, data);
            pushService.sendMessageByAdmin(pushContentByAdmin);
            SendMessageUtils.newOrder2Service(orderDto, orderDetailDto);
        }
        //后付费模式时 执行自动派单或者推单逻辑
        if (orderDto.getPayPattern().equals(OrderConstant.ORDER_PAY_PATTERN_AFTER)) {
            log.info("订单：{} 后付费，执行自动派单逻辑", orderDto.getUuid());
            try {
                CrosstownAssignOrderParam crosstownAssignOrderParam = new CrosstownAssignOrderParam();
                //订单信息线路信息由下单信息传过去 不再重新查库
                crosstownAssignOrderParam.setCurrentOrderDto(orderDto);
                crosstownAssignOrderParam.setCurrentOrderDetailDto(orderDetailDto);
                crosstownAssignOrderParam.setCurrentOrderFareDto(orderFareDto);
                crosstownAssignOrderParam.setCurrentOrderUuid(orderDto.getUuid());
                crosstownAssignOrderParam.setSysWayDto(sysWayDto);
                OrderHandleThreadPoolUtil.execute(() -> orderAssignService.doAssignCrosstownOrderAuto(crosstownAssignOrderParam));
            } catch (Exception e) {
                e.printStackTrace();
                log.info("订单：{} 下单完成，自动派单逻辑发生异常", orderDto.getUuid());
            }
        }
        return buildNewOrderResult(orderDto, orderDetailDto);
    }

    /**
     * 删除订单
     * @return
     */
    private void deleteOrderInfo(OrderDto orderDto,OrderDetailDto orderDetailDto,OrderFareDto orderFareDto){
        orderMapper.del(orderDto);
        orderDetailMapper.del(orderDetailDto);
        orderFareMapper.del(orderFareDto);
    }

    /**
     * 构造订单返回值
     *
     * @param orderDto
     * @param orderDetailDto
     * @return
     */
    private ResponseData<Map<String, Object>> buildNewOrderResult(OrderDto orderDto, OrderDetailDto orderDetailDto) {
        //临时使用 未知移动端具体使用字段 暂时不重新查库
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.putAll(MapUtils.convertObjToMap(orderDetailDto));
        resultMap.putAll(MapUtils.convertObjToMap(orderDto));
        return ResponseData.buildSuccessResponse(resultMap);
    }

    /**
     * 跨城订单逻辑校验
     */
    private ResponseData crosstownOrderLogicCheck(JoinOrderParam joinOrderParam, SysWayDto sysWayDto) {
        //是否小件订单
        boolean isParcelOrder = joinOrderParam.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL;
        PassengerDto passengerDto = joinOrderParam.getPassengerDto();
        //起终点坐标判定&设置
        if (sysWayDto.getOriginType() == OrderConstant.POINT_SITE_TYPE_AREA) {
            if (null == joinOrderParam.getOriginLng() || joinOrderParam.getOriginLng() <= 0
                    || null == joinOrderParam.getOriginLng() || joinOrderParam.getOriginLat() <= 0) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "起点坐标缺失或异常");
            }
            if (!OrderAssignHelper.joinWayMatch(joinOrderParam.getAppid(), joinOrderParam.getOriginLng(), joinOrderParam.getOriginLat(),
                    sysWayDto.getOriginType(), sysWayDto.getOriginIncludeAreas(), sysWayDto.getOriginCityName(),
                    sysWayDto.getOriginLng(), sysWayDto.getOriginLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "起点坐标不在线路起点服务范围内");
            }
        }
        if (sysWayDto.getDestType() == OrderConstant.POINT_SITE_TYPE_AREA) {
            if (null == joinOrderParam.getDestLng() || joinOrderParam.getDestLng() <= 0 || null == joinOrderParam
                    .getDestLat() || joinOrderParam.getDestLat() <= 0) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "终点坐标缺失或异常");
            }
            if (!OrderAssignHelper.joinWayMatch(joinOrderParam.getAppid(), joinOrderParam.getDestLng(), joinOrderParam.getDestLat(),
                    sysWayDto.getDestType(), sysWayDto.getDestIncludeAreas(), sysWayDto.getDestCityName(),
                    sysWayDto.getDestLng(), sysWayDto.getDestLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "终点坐标不在线路终点服务范围内");
            }
        }

        Date nowDate = new Date();
        //查看出发时间是否限制
        AdminDepartLimitPageParam systemDepartLimitParam = new AdminDepartLimitPageParam();
        systemDepartLimitParam.setLimitWayUuid(sysWayDto.getUuid());
        systemDepartLimitParam.setDeparTime(joinOrderParam.getDeparTime());
        ResponseData<Boolean> deparLimitRsd = sysDepartLimitService.checkDepartLimit(systemDepartLimitParam);
        if (!deparLimitRsd.isSuccess()) {
            //出发时间校验未通过
            return ResponseData.buildErrorResponse(deparLimitRsd.getErrCode(), deparLimitRsd.getMsg());
        }

        //不超过7天校验
        if (joinOrderParam.getDeparTime().after(CalendarUtil.dayPlus(nowDate, 7))) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "出发时间请选择七天之内");
        }
        //线路运营时间判断
        Date tempDepartTime = DateUtils.parse(DateUtils.format(joinOrderParam.getDeparTime(), "HH:mm"), "HH:mm");
        if (tempDepartTime.before(sysWayDto.getStartTime()) || tempDepartTime.after(sysWayDto.getEndTime())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "非路线运营时间");
        }
        String checkPassengerMobile;
        //此处区分小件与拼车订单校验
        if (isParcelOrder) {
            //小件订单校验
            //小件订单的乘客只需判断当前下单账户
            checkPassengerMobile = passengerDto.getMobile();
        } else {
            //跨城订单校验
            //人数校验
            if (null == joinOrderParam.getAdultNum() || joinOrderParam.getAdultNum() == 0) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "至少需要一名成人乘客");
            }
            //拼车订单乘客需要优先判断实际乘客
            checkPassengerMobile = ParamUtil.defaultIfNull(joinOrderParam.getActualMobile(), passengerDto.getMobile());
        }

//        //判断能否下单
        ResponseData<Boolean> result = orderRiskControlService.canPasCreateOrder(passengerDto.getUuid(),
                joinOrderParam.getAppid(), CommonConstant.BUSINESS_TYPE_POOL,checkPassengerMobile,isParcelOrder?null:joinOrderParam.getTypeTime());
        if (!result.isSuccess()) {
            //乘客下单校验未通过
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, result.getMsg());
        }
        return ResponseData.buildSuccessResponse("校验通过");
    }


    /**
     * 获取线路信息
     */
    private SysWayDto getWayInfo(JoinOrderParam joinOrderParam) {
        Map<String, Object> map = MapUtils.build();
        map.put("originSiteUuid", joinOrderParam.getOriginSiteUuid());
        map.put("destSiteUuid", joinOrderParam.getDestSiteUuid());
        map.put("appid", joinOrderParam.getAppid());
        //小件增加开关条件
        if (joinOrderParam.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL) {
            map.put("parcelStatus", CommonConstant.STATUS_OPENED);
            map.put("state", CommonConstant.STATE_NORMAL);
        }
        ResponseData<List<SysWayDto>> wayRsd = sysWayService.findWithOriginDest(map);
        if (CollectionUtils.isEmpty(wayRsd.getData())) {
            return null;
        }
        return wayRsd.getData().get(0);
    }

    /**
     * 获取乘客信息
     */
    private PassengerDto getPassengerInfo(JoinOrderParam joinOrderParam) {
        PassengerDto passengerDto = new PassengerDto();
        if (StringUtils.isNotEmpty(joinOrderParam.getPassengerUuid())) {
            passengerDto = passengerService.get(joinOrderParam.getPassengerUuid()).getData();
        } else if (StringUtils.isNotEmpty(joinOrderParam.getPassengerMobile())) {
            passengerDto = passengerService.get(MapUtils.build("mobile", joinOrderParam.getPassengerMobile())).getData();
        }
        if (passengerDto == null && StringUtils.isNotEmpty(joinOrderParam.getActualMobile())) {
            String passengerName = "用户" + StringUtils.right(joinOrderParam.getActualMobile(), 4);
            passengerDto = PassengerHelper.newPassenger(joinOrderParam.getActualMobile(), passengerName, joinOrderParam.getAppid());
        }
        return passengerDto;
    }

    /**
     * 获取路线
     */
    private ResponseData<List<SysWayDto>> verifyWay(JoinOrderParam joinOrderParam) {
        Map<String, Object> map = MapUtils.build();
        map.put("originSiteUuid", joinOrderParam.getOriginSiteUuid());
        map.put("destSiteUuid", joinOrderParam.getDestSiteUuid());
        map.put("appid", joinOrderParam.getAppid());
        //小件增加开关条件
        if (joinOrderParam.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL) {
            map.put("parcelStatus", CommonConstant.STATUS_OPENED);
            map.put("state", CommonConstant.STATE_NORMAL);
        }
        return sysWayService.findWithOriginDest(map);
    }

    /**
     * 起终点坐标设置与校验
     */
    private ResponseData<Void> coordinateSetting(JoinOrderParam joinOrderParam, SysWayDto sysWayDto) {
        //路线按照区域时，判定坐标是否区域，不在区域内时，使用路线设置的起终点中心位置
        if (sysWayDto.getOriginType() == POINT_SITE_TYPE_AREA) {
            if (!OrderAssignHelper.joinWayMatch(joinOrderParam.getAppid(), joinOrderParam.getOriginLng(), joinOrderParam.getOriginLat(),
                    sysWayDto.getOriginType(), sysWayDto.getOriginIncludeAreas(), sysWayDto.getOriginCityName(),
                    sysWayDto.getOriginLng(), sysWayDto.getOriginLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "起点坐标不在线路起点服务范围内");
            }
        } else {
            joinOrderParam.setOriginLng(sysWayDto.getOriginLng());
            joinOrderParam.setOriginLat(sysWayDto.getOriginLat());
        }
        if (sysWayDto.getDestType() == POINT_SITE_TYPE_AREA) {
            if (null == joinOrderParam.getDestLng() || joinOrderParam.getDestLng() <= 0 ||
                    null == joinOrderParam.getDestLat() || joinOrderParam.getDestLat() <= 0) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "终点坐标缺失或异常");
            }
            if (!OrderAssignHelper.joinWayMatch(joinOrderParam.getAppid(), joinOrderParam.getDestLng(), joinOrderParam.getDestLat(),
                    sysWayDto.getDestType(), sysWayDto.getDestIncludeAreas(), sysWayDto.getDestCityName(),
                    sysWayDto.getDestLng(), sysWayDto.getDestLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "终点坐标不在线路终点服务范围内");
            }
        } else {
            joinOrderParam.setDestLng(sysWayDto.getDestLng());
            joinOrderParam.setDestLat(sysWayDto.getDestLat());
        }
        return ResponseData.buildSuccessResponse("设置完成", null);
    }

    /**
     * 初始化订单信息
     */
    private void initOrderInfo(JoinOrderParam joinOrderParam, SysWayDto sysWayDto, OrderDto orderDto, OrderDetailDto orderDetailDto, OrderFareDto orderFareDto) {
        Date nowDate = new Date();
        //是否是小件订单
        boolean isParcelOrder = joinOrderParam.getTypeModule() == CommonConstant.BUSINESS_TYPE_PARCEL;
        PassengerDto passengerDto = joinOrderParam.getPassengerDto();
        orderDto.setUuid(StringUtils.buildUUID());
        orderDto.setPassengerUuid(passengerDto.getUuid());
        orderDto.setTypeEnt(ORDER_TYPE_ENT_PER);//订单类型（个人/企业）：1 个人；2 企业
        orderDto.setTypeSelf(ORDER_TYPE_SELF_ME);//订单类型（本人/代客）：1 本人；2 代客
        orderDto.setTypeMain(ORDER_TYPE_CHILD);//订单类型（主/子订单）：1 主订单；2 子订单

        orderDto.setSource(ParamUtil.defaultIfNull(joinOrderParam.getOrderSource(), ORDER_SOURCE_APP));//订单来源：1 APP移动端；2 微信公众号；3 电话叫车；4 pc网站； 5 后台下单； 6 小程序下单
        orderDto.setPayStatus(Constants.ORDER_PAY_STATUS_UNPAY);//支付状态：0未支付 1已支付 2退款中 3已退款
        orderDto.setPrepayType(PREPAY_TYPE_OWN);//预支付方式（1企业支付，2个人支付）
        orderDto.setAppid(joinOrderParam.getAppid());
        orderDto.setIsBilled(ORDER_IS_BILLED_UNGENERATE);
        orderDto.setIsAllowAssigned(ORDER_ALLOW_ASSIGNED_ENABLED);
        orderDto.setPassengerLng(joinOrderParam.getPassengerLng());
        orderDto.setPassengerLat(joinOrderParam.getPassengerLat());
        orderDto.setTypeModule(joinOrderParam.getTypeModule());
        orderDto.setTypeTrip(1);
        orderDto.setTypeTime(joinOrderParam.getTypeTime());
        orderDto.setCarModelUuid(joinOrderParam.getCarModelUuid());
        orderDto.setWayUuid(sysWayDto.getUuid());
        orderDto.setCloseStatus(ORDER_CLOSE_STATUS_NORMAL);
        orderDto.setTypeJoin(joinOrderParam.getTypeJoin());
        orderDto.setOrderDemand(joinOrderParam.getOrderDemand());
        orderDto.setMainStatus(ORDER_MAIN_STATUS_INITIAL);
        orderDto.setSubStatus(ORDER_STATUS_FARE_CONFIRM);
        orderDto.setTypeInteractive(OrderConstant.NEW_ORDER_TYPE_INTERACTIVE_SNATCH);
        orderDto.setCreateOn(nowDate);


        //预约单唯一不同的字段
        orderDetailDto.setUuid(StringUtils.buildUUID());
        orderDetailDto.setOrderUuid(orderDto.getUuid());
        orderDetailDto.setDeparTime(joinOrderParam.getDeparTime());
        String originCity = joinOrderParam.getOriginCity();
        originCity = StringUtils.isEmpty(originCity) ? sysWayDto.getOriginCityName() : originCity;

        orderDetailDto.setOriginCityUuid(sysCityService.getCityUuidByName(originCity).getData());
        orderDetailDto.setOriginCity(originCity);
        orderDetailDto.setOriginLng(joinOrderParam.getOriginLng());
        orderDetailDto.setOriginLat(joinOrderParam.getOriginLat());
        orderDetailDto.setOriginAddress(StringUtils.isEmpty(joinOrderParam.getOriginAddress()) ? sysWayDto.getOriginName() : joinOrderParam.getOriginAddress());
        orderDetailDto.setOriginDetailAddress(StringUtils.isEmpty(joinOrderParam.getOriginDetailAddress()) ? orderDetailDto.getOriginAddress() : joinOrderParam.getOriginDetailAddress());

        orderDetailDto.setDestAddress(StringUtils.isEmpty(joinOrderParam.getDestAddress()) ? sysWayDto.getDestName() : joinOrderParam.getDestAddress());
        orderDetailDto.setDestDetailAddress(StringUtils.isEmpty(joinOrderParam.getDestDetailAddress()) ? orderDetailDto.getDestAddress() : joinOrderParam.getDestDetailAddress());
        orderDetailDto.setDestLng(joinOrderParam.getDestLng());
        orderDetailDto.setDestLat(joinOrderParam.getDestLat());

        String destCity = joinOrderParam.getDestCity();
        destCity = StringUtils.isEmpty(destCity) ? sysWayDto.getDestCityName() : destCity;
        orderDetailDto.setDestCityUuid(sysCityService.getCityUuidByName(destCity).getData());
        orderDetailDto.setDestCity(destCity);

        orderDetailDto.setTip(0d);
        orderDetailDto.setIsMetered(ORDER_METERED_FASEL);
        orderDetailDto.setOriginAreaCode(joinOrderParam.getOriginAreaCode());
        //备注
        orderDetailDto.setRemark(joinOrderParam.getRemark());
        orderDetailDto.setCreateOn(nowDate);

        orderFareDto.setUuid(StringUtils.buildUUID());
        orderFareDto.setOrderUuid(orderDto.getUuid());
        orderFareDto.setCreateOn(nowDate);
        //此处区分跨城与小件不同的字段处理
        if (isParcelOrder) {
            //小件订单处理
            //小件为先付费模式
            orderDto.setPayPattern(ORDER_PAY_PATTERN_FRONT);
            orderDto.setJoinStatus(ORDER_JOIN_STATUS_INIT);
            orderDto.setSeatNum(0);
            orderDto.setTypeJoin(CommonConstant.ORDER_TYPE_JOIN_PARCEL);
            orderDetailDto.setActualPasNam(joinOrderParam.getSenderName());
            orderDetailDto.setActualPasMob(joinOrderParam.getSenderMobile());
            orderDetailDto.setActualPasNum(0);
            orderDetailDto.setAdultNum(0);
            //货件相关信息
            orderDetailDto.setSenderName(joinOrderParam.getSenderName());
            orderDetailDto.setSenderMobile(joinOrderParam.getSenderMobile());
            orderDetailDto.setReceiverName(joinOrderParam.getReceiverName());
            orderDetailDto.setReceiverMobile(joinOrderParam.getReceiverMobile());
            orderDetailDto.setParcelPhoto(joinOrderParam.getParcelPhoto());
            //生成四位收件码
            int random = Double.valueOf(Math.random() * 10000).intValue();
            orderDetailDto.setReceiptCode(String.format("%04d", random));
            orderDetailDto.setParcelInfoCode(joinOrderParam.getParcelTypeCode()
                    + "," + joinOrderParam.getParcelWeightCode() + "," + joinOrderParam.getParcelVolumeCode());
            orderDetailDto.setParcelInfoName(joinOrderParam.getParcelInfoName());

            //获取最新价格
            ResponseData<Map<String, Object>> fareRsd = orderFareService.parcelValuation(joinOrderParam);

            //订单价格表
            orderFareDto.setCreateOn(new Date());
            Map fareRSData = fareRsd.getData();
            //总价
            orderFareDto.setTotalFare(null != fareRSData.get("totalFare") ? (Double) fareRSData.get("totalFare") : 0d);
            orderFareDto.setLatestOrderFare(BigDecimal.valueOf(orderFareDto.getTotalFare()));
            Double orderFare = Double.parseDouble(fareRSData.get(PARCEL_FIXED_PRICE_KEY).toString());
            orderFareDto.setOrderFare(BigDecimal.valueOf(orderFare));
            //小件订单加价等于总价 - 一口价
            orderFareDto.setParcelRaisePrice(orderFareDto.getTotalFare() - orderFare);
        } else {
            //跨城订单处理
            Integer payPattern;
            try {
                //false = 1 = 先付费 , true = 2 = 后付费
                payPattern = ApplicationConfig.DRIVER_CONFIG.getDriverPay().getJoin().getPayPattern() ? 2 : 1;
            } catch (Exception e) {
                log.info("付费模式获取失败{}", e);
                payPattern = 2;
            }
            orderDto.setPayPattern(payPattern);
            orderDto.setSeatNum(joinOrderParam.getAdultNum());
            if (orderDto.getPayPattern().equals(OrderConstant.ORDER_PAY_PATTERN_FRONT)) {
                orderDto.setJoinStatus(ORDER_JOIN_STATUS_INIT);
            } else {
                //后付费模式 直接进入预约成功
                orderDto.setJoinStatus(OrderConstant.ORDER_JOIN_STATUS_SUB_OK);
            }
            //乘车人数
            orderDetailDto.setAdultNum(joinOrderParam.getAdultNum());
            orderDetailDto.setActualPasNum(joinOrderParam.getAdultNum());
            orderDetailDto.setActualPasMob(StringUtils.isEmpty(joinOrderParam.getActualMobile()) ? joinOrderParam.getPassengerMobile() : joinOrderParam.getActualMobile());
            orderDetailDto.setActualPasNam(joinOrderParam.getActualName());
            //获取最新价格
            OrderEvaluateParam orderEvaluateParam = new OrderEvaluateParam();
            BeanUtils.copyProperties(joinOrderParam, orderEvaluateParam);
            orderEvaluateParam.setOriginUuid(joinOrderParam.getOriginSiteUuid());
            orderEvaluateParam.setDestUuid(joinOrderParam.getDestSiteUuid());
            ResponseData<ApiJoinValuationVo> joinValuation = orderFareService.joinValuation(orderEvaluateParam);
            if (joinValuation.isSuccess()) {
                ApiJoinValuationVo joinValuationVo = joinValuation.getData();
                Double aDouble = ParamUtil.defaultIfNull(joinValuationVo.getTotalFare(), 0D);
                orderFareDto.setTotalFare(aDouble);
                orderFareDto.setLatestOrderFare(BigDecimal.valueOf(aDouble));
                orderFareDto.setOriginRaisePrice(joinValuationVo.getOriginRaisePrice());
                orderFareDto.setDestRaisePrice(joinValuationVo.getDestRaisePrice());
                orderFareDto.setNightRaisePrice(joinValuationVo.getNightRaisePrice());
                orderFareDto.setOrderFare(BigDecimal.valueOf(joinValuationVo.getOrderFare()));
            }
        }

        //后台下单不走支付回调流程，业务分离
        if (ORDER_SOURCE_ADMIN == joinOrderParam.getOrderSource() || ORDER_SOURCE_PHONE == joinOrderParam.getOrderSource()) {
            //直接转入预约成功状态、等待后台派单
            orderDto.setJoinStatus(OrderConstant.ORDER_JOIN_STATUS_SUB_OK);
            //后台下单默认后付费
            orderDto.setPayPattern(OrderConstant.ORDER_PAY_PATTERN_AFTER);
        }
    }

    @Override
    public ResponseData<List<Map<String, Object>>> getReceiptCode(JoinOrderParam joinOrderParam) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        if (joinOrderParam.getMainOrderUuid() != null) {
            paramsMap.put("mainOrderUuid", joinOrderParam.getMainOrderUuid());
        }
        if (joinOrderParam.getOrderUuid() != null) {
            paramsMap.put("uuid", joinOrderParam.getOrderUuid());
        }
        List<JsonOrderDetailVo> list = orderMapper.getReceiptCode(paramsMap);
        if (list == null || list.size() == 0) {
            return ResponseData.buildErrorResponse(0, "获取收货码失败");
        }
        List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
        for (JsonOrderDetailVo jsonOrderDetailVo : list) {
            Map<String, Object> resultMap = new HashMap<String, Object>();
            //乘客端获取时，返回初始收货码，司机端获取时，返回确认收货码
            if (joinOrderParam.getOrderUuid() != null) {
                resultMap.put("receiptCode", jsonOrderDetailVo.getReceiptCode());
            } else {
                resultMap.put("receiverName", jsonOrderDetailVo.getReceiverName());
                resultMap.put("receiverMobile", jsonOrderDetailVo.getReceiverMobile());
                resultMap.put("orderUuid", jsonOrderDetailVo.getOrderUuid());
                resultMap.put("receiptCode", jsonOrderDetailVo.getConfirmReceiptCode());
            }
            resultList.add(resultMap);
        }
        return ResponseData.buildSuccessResponse("获取收货码成功", resultList);
    }

    @Override
    public ResponseData<Boolean> confirmReceiptCode(JoinOrderParam joinOrderParam) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        paramsMap.put("uuid", joinOrderParam.getOrderUuid());
        paramsMap.put("receiptCode", joinOrderParam.getReceiptCode());
        List<JsonOrderDetailVo> list = orderMapper.getReceiptCode(paramsMap);
        if (list == null || list.size() == 0) {
            return ResponseData.buildErrorResponse(0, "收货码错误，请核对后再确认收货");
        }
        OrderDetailDto orderDetailDto = new OrderDetailDto();
        orderDetailDto.setConfirmReceiptCode(joinOrderParam.getReceiptCode());
        orderDetailDto.setOrderUuid(joinOrderParam.getOrderUuid());
        int result = orderDetailMapper.updateByOrderUuid(orderDetailDto);
        if (result == 0) {
            ResponseData.buildErrorResponse(0, "保存收货码失败，请稍后重试");
        }
        return ResponseData.buildSuccessResponse("收货码确认成功", true);
    }

    @Override
    public ResponseData<Map<String, Object>> getParcelTag(JoinOrderParam joinOrderParam) {
        //获取路线
        Map<String, Object> paraMap = MapUtils.build();
        paraMap.put("originSiteUuid", joinOrderParam.getOriginSiteUuid());
        paraMap.put("destSiteUuid", joinOrderParam.getDestSiteUuid());
        paraMap.put("state", CommonConstant.STATE_NORMAL);
        paraMap.put("parcelStatus", CommonConstant.STATUS_OPENED);
        paraMap.put("appid", joinOrderParam.getAppid());
        ResponseData<SysWayDto> wayRs = sysWayService.get(paraMap);
        if (!wayRs.isSuccess()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "估价失败：路线异常或不存在");
        }
        SysWayDto sysWayDto = wayRs.getData();
        //获取车型
        ResponseData<CarModelDto> carmodelRsd = carModelService.get(MapUtils.build("businessType", CommonConstant.BUSINESS_TYPE_PARCEL));
        if (!carmodelRsd.isSuccess()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "估价失败：获取车型信息失败");
        }
        CarModelDto carModelDto = carmodelRsd.getData();
        //获取路线价格
        paraMap.clear();
        paraMap.put("wayUuid", sysWayDto.getUuid());
        paraMap.put("carModelUuid", carModelDto.getUuid());
        log.info("查询价格参数{}", paraMap);
        ResponseData<SysWayCalculationDto> responseData = sysWayCalculationService.findOne(paraMap);
        if (!responseData.isSuccess()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "估价失败：获取路线价格失败");
        }
        SysWayCalculationDto sysWayCalculationDto = responseData.getData();
        //取出价格设置json
        JsonNode priceJson = null;
        try {
            priceJson = JsonUtils.readNode(sysWayCalculationDto.getParcelPrice());
        } catch (IOException e) {
            log.error("JsonUtils readNode error. {}", sysWayCalculationDto.getParcelPrice(), e);
        }
        //获取跨城小件标签
        paraMap.clear();
        paraMap.put("businessType", CommonConstant.BUSINESS_TYPE_PARCEL);
        paraMap.put("appid", joinOrderParam.getAppid());

        List<CommonTagDto> tagList = commonTagService.list(paraMap).getData();
        if (CollectionUtils.isEmpty(tagList)) {
            ResponseData.buildErrorResponse(0, "跨城小件标签获取失败");
        }
        //分组标签 并关联线路的货件加价设置
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> parcelTypeList = new ArrayList<>();
        List<Map<String, Object>> parcelWeightList = new ArrayList<>();
        List<Map<String, Object>> parcelVolumeList = new ArrayList<>();
        for (CommonTagDto commonTagDto : tagList) {
            String tagCode = commonTagDto.getTagCode();
            String tagName = commonTagDto.getTagName();
            Integer tagType = commonTagDto.getTagType();
            Map<String, Object> parcelInfoMap = new HashMap<>();
            parcelInfoMap.put("tagCode", tagCode);
            parcelInfoMap.put("tagName", tagName);
            //货件类型 货件重量 货件体积
            if (CommonConstant.TAG_TYPE_PARCEL_TYPE == tagType) {
                parcelTypeList.add(parcelInfoMap);
            } else if (CommonConstant.TAG_TYPE_PARCEL_WEIGHT == tagType) {
                parcelWeightList.add(parcelInfoMap);
            } else if (CommonConstant.TAG_TYPE_PARCEL_VOLUME == tagType) {
                //一口价时 加价未0 其他体积类型按照实际赋值
                if (PARCEL_FIXED_PRICE_KEY.equals(tagCode)) {
                    parcelInfoMap.put("raisePrice", 0);
                } else {
                    parcelInfoMap.put("raisePrice", priceJson.get(tagCode).asDouble());
                }
                parcelVolumeList.add(parcelInfoMap);
            }
        }
        resultMap.put("sysWayCalculationUuid", sysWayCalculationDto.getUuid());
        resultMap.put("parcelType", parcelTypeList);
        resultMap.put("parcelWeight", parcelWeightList);
        resultMap.put("parcelVolume", parcelVolumeList);
        return ResponseData.buildSuccessResponse("跨城小件标签获取成功", resultMap);
    }

    @Override
    public ResponseData<Boolean> orderSequenceChange(List<CrosstownOrderParam> paramList) {
        int result = orderMapper.orderSequenceChange(paramList);
        if (result > 0) {
            //推送乘客告知订单顺序变更
            Map<String, Object> paraMap = new HashMap<>();
            String mainOrderUuid = paramList.get(0).getMainOrderUuid();
            String appid = paramList.get(0).getAppid();
            paraMap.put("mainOrderUuid", mainOrderUuid);
            paraMap.put("closeStatus", ORDER_CLOSE_STATUS_NORMAL);

            List<AllPassengerOrderVo> list = orderMapper.allPassengerOrderInfo(paraMap);
            if (list != null && list.size() > 0) {
                List<String> passengerUuidList = new ArrayList<>();
                for (AllPassengerOrderVo allPassengerOrderVo : list) {
                    if (allPassengerOrderVo.getJoinStatus() < ORDER_JOIN_STATUS_COMPLETED) {
                        passengerUuidList.add(allPassengerOrderVo.getPassengerUuid());
                    }
                }
                /*消息推送*/
                pushListOrder2Pas(passengerUuidList, mainOrderUuid, appid, "行程信息更新通知", "拼友信息已更新，您可在订单查看订单最新动态",
                        ORDER_JOIN_PAS_ORDER_REFRESH, MapUtils.build("mainOrderUuid", mainOrderUuid));
            }
            return ResponseData.buildSuccessResponse("更新成功", true);
        }
        return ResponseData.buildErrorResponse(0, "更新失败");
    }

    @Override
    public ResponseData<PageList<CrosstownOrderVo>> crosstownOrderListInfo(CrosstownOrderParam crosstownOrderParam, Integer type) {
        PageBounds pageBounds = new PageBounds(crosstownOrderParam.getNowPage(), crosstownOrderParam.getPageSize());
        Map<String, Object> objectMap = MapUtils.convertObjToMap(crosstownOrderParam);
        objectMap.put("type", type);
        PageList<CrosstownOrderVo> pageList = orderMapper.crosstownOrderListInfo(objectMap, pageBounds);
        //取出第一个订单的起终点位置 出发时间放入返回值主信息
        for (CrosstownOrderVo crosstownOrderVo : pageList) {
            List<SimpleOrderInfoVo> simpleOrderInfoVoList = crosstownOrderVo.getOrderInfoList();
            if (CollectionUtils.isNotEmpty(simpleOrderInfoVoList)) {
                SimpleOrderInfoVo simpleOrderInfoVo = simpleOrderInfoVoList.get(0);
                crosstownOrderVo.setDeparTime(simpleOrderInfoVo.getDeparTime());
                crosstownOrderVo.setOriginAddress(simpleOrderInfoVo.getOriginAddress());
                crosstownOrderVo.setDestAddress(simpleOrderInfoVo.getDestAddress());
                crosstownOrderVo.setOriginSite(simpleOrderInfoVo.getOriginSite());
                crosstownOrderVo.setDestSite(simpleOrderInfoVo.getDestSite());
                //设置主单类型是包车或者二人快车或者拼车单（小件与拼车都为拼车单）
                if (CommonConstant.ORDER_TYPE_JOIN_CHARTERED == simpleOrderInfoVo.getTypeJoin()) {
                    crosstownOrderVo.setTypeJoin(CommonConstant.ORDER_TYPE_JOIN_CHARTERED);
                } else if (CommonConstant.ORDER_TYPE_JOIN_TWO_PERSONS == simpleOrderInfoVo.getTypeJoin()) {
                    crosstownOrderVo.setTypeJoin(CommonConstant.ORDER_TYPE_JOIN_TWO_PERSONS);
                } else {
                    crosstownOrderVo.setTypeJoin(CommonConstant.ORDER_TYPE_JOIN_ORDINARY);
                }
            }
            //设置订单类型
            Double orderTotalFare = 0d;
            Double unpaidTotalFare = 0d;
            Integer orderPasSum = 0;
            Integer orderParcelSum = 0;
            for (SimpleOrderInfoVo simpleOrderInfoVo : simpleOrderInfoVoList) {
                Integer closeStatus = simpleOrderInfoVo.getCloseStatus();
                Integer payStatus = simpleOrderInfoVo.getPayStatus();
                if (closeStatus != null && closeStatus !=OrderConstant.ORDER_CLOSE_STATUS_NORMAL){
                    continue;
                }
                if (CommonConstant.ORDER_TYPE_JOIN_PARCEL == simpleOrderInfoVo.getTypeJoin()) {
                    orderParcelSum += 1;
                } else {
                    orderPasSum += simpleOrderInfoVo.getPassengerNum();
                }
                orderTotalFare = orderTotalFare + simpleOrderInfoVo.getTotalFare();
                if (payStatus !=null && payStatus.equals(OrderConstant.ORDER_PAY_STATUS_WAIT_PAY)) {
                    unpaidTotalFare = unpaidTotalFare + simpleOrderInfoVo.getTotalFare();
                }
            }
            crosstownOrderVo.setOrderSum(simpleOrderInfoVoList.size());
            crosstownOrderVo.setOrderPasSum(orderPasSum);
            crosstownOrderVo.setOrderParcelSum(orderParcelSum);
            crosstownOrderVo.setOrderTotalFare(orderTotalFare);
            crosstownOrderVo.setUnpaidTotalFare(unpaidTotalFare);
        }
        return ResponseData.buildSuccessResponse(pageList);
    }

    @Override
    public ResponseData crosstownOrderListDetail(CrosstownOrderParam crosstownOrderParam) {
        List<CrosstownOrderDetailVo> crosstownOrderList = orderMapper.crosstownOrderListDetail(MapUtils.convertObjToMap(crosstownOrderParam));
        if (CollectionUtils.isEmpty(crosstownOrderList)) {
            return ResponseData.buildSuccessResponse(new HashMap<>(2));
        }
        //返回值
        CrosstownDriverOrderDetailVo resultVo = new CrosstownDriverOrderDetailVo();
        Integer mainJoinStatus = crosstownOrderList.get(0).getMainJoinStatus();
        Integer mainCloseStatus = crosstownOrderList.get(0).getMainCloseStatus();
        Integer mainTypeJoin = crosstownOrderList.get(0).getTypeJoin();
        String wayUuid = crosstownOrderList.get(0).getWayUuid();
        resultVo.setOrderInfoList(crosstownOrderList);
        resultVo.setMainJoinStatus(mainJoinStatus);
        resultVo.setMainCloseStatus(mainCloseStatus);
        resultVo.setDeparTime(crosstownOrderList.get(0).getDeparTime());
        //当订单未完成时，返回线路的围栏信息  当前订单完成状态时，返回订单的定位点集合
        if (mainJoinStatus < ORDER_JOIN_STATUS_PART_NO_PAY) {
            List<WayfenceInfoVo> fenceList = sysWayFenceService.queryWayFenceInfo(wayUuid).getData();
            resultVo.setWayfenceInfoList(fenceList);
        } else {
            Map<String, Object> paraMap = new HashMap<>();
            paraMap.put("mainOrderUuid", crosstownOrderParam.getMainOrderUuid());
            paraMap.put("appid", crosstownOrderParam.getAppid());
            //通过缓存获取定位点 如果未找到 则重新查询
            String cacheLocationKey = "COMPLETE_ORDER_LOCATION" + crosstownOrderParam.getMainOrderUuid() + crosstownOrderParam.getAppid();
            List<DriverLocation> driverLocationList;
            Object cacheLocation = redisCacheService.get(cacheLocationKey);
            if (cacheLocation != null) {
                driverLocationList = (List<DriverLocation>) cacheLocation;
            } else {
                driverLocationList = locationService.getCrosstownOrderLocation(paraMap).getData();
                if (CollectionUtils.isNotEmpty(driverLocationList)) {
                    redisCacheService.set(cacheLocationKey, driverLocationList, 24L, TimeUnit.HOURS);
                }
            }
            Map<String, Object> driverDepartPoint = new HashMap<>();
            List<Map<String, Object>> passengerGetOnPointList = new ArrayList<>();
            List<Map<String, Object>> passengerGetOffPointList = new ArrayList<>();
            //所有订单中抽取部分点
            List<LatLngDto> tracePointList = new ArrayList<>();
            for (int i = 0; i < driverLocationList.size(); i++) {
                DriverLocation driverLocation = driverLocationList.get(i);
                Coordinate coordinate = driverLocation.getCoordinate();
                //司机出发点 410
                if (driverLocation.getPositionType() != null) {
                    driverDepartPoint.put("lng", coordinate.getLng());
                    driverDepartPoint.put("lat", coordinate.getLat());
                }
                //乘客上车 430
                if (driverLocation.getOrderUuid() != null && driverLocation.getJoinStatus() == ORDER_JOIN_STATUS_PASSENGER_ABOARD) {
                    Map<String, Object> getOnPointMap = new HashMap<>();
                    getOnPointMap.put("orderUuid", driverLocation.getOrderUuid());
                    getOnPointMap.put("lng", coordinate.getLng());
                    getOnPointMap.put("lat", coordinate.getLat());
                    passengerGetOnPointList.add(getOnPointMap);
                    setPointList(tracePointList, coordinate);
                }
                //乘客下车 订单完成 600
                if (driverLocation.getOrderUuid() != null && driverLocation.getJoinStatus() == ORDER_JOIN_STATUS_COMPLETED) {
                    Map<String, Object> getOffPointMap = new HashMap<>();
                    getOffPointMap.put("orderUuid", driverLocation.getOrderUuid());
                    getOffPointMap.put("lng", coordinate.getLng());
                    getOffPointMap.put("lat", coordinate.getLat());
                    passengerGetOffPointList.add(getOffPointMap);
                    setPointList(tracePointList, coordinate);
                }
                //3分钟取出一个点 按照15s一个点计算 3分钟12个点
                if (i % 12 == 0) {
                    setPointList(tracePointList, coordinate);
                } else if (i == driverLocationList.size() - 1) {
                    setPointList(tracePointList, coordinate);
                }
            }
            Map<String, Object> pointsMap = new HashMap<>();
            //司机出发点
            pointsMap.put("driverDepartPoint", driverDepartPoint);
            //乘客上车点
            pointsMap.put("passengerGetOnPoint", passengerGetOnPointList);
            //乘客下车点
            pointsMap.put("passengerGetOffPoint", passengerGetOffPointList);
            resultVo.setSpecialPoints(pointsMap);
            if (tracePointList.size() > 0) {
                resultVo.setTracePoints(PolylineUtils.encodePoly(tracePointList));
            }
        }
        return ResponseData.buildSuccessResponse("查询成功", resultVo);
    }

    /**
     * 设置定位点集合
     */
    private void setPointList(List<LatLngDto> list, Coordinate coordinate) {
        LatLngDto latLngDto = new LatLngDto();
        latLngDto.setLatitude(coordinate.getLat());
        latLngDto.setLongitude(coordinate.getLng());
        list.add(latLngDto);
    }

    /**
     * 司机变更订单状态 跟订单当前状态 判断下个逻辑的执行方法
     *
     * @param crosstownOrderParam
     * @return
     */
    @Override
    public ResponseData crosstownOrderStateChange(CrosstownOrderParam crosstownOrderParam) {
        switch (crosstownOrderParam.getJoinStatus()) {
            //司机出发
            case OrderConstant.ORDER_JOIN_STATUS_DRIVER_DEPARTURE: {
                return crosstownOrderProcessor.tripBegan(crosstownOrderParam);
            }
            //到达上车点
            case OrderConstant.ORDER_JOIN_STATUS_ARRIVE_POINT: {
                return crosstownOrderProcessor.arriveGetOnPoint(crosstownOrderParam);
            }
            //已上车（已取件）
            case OrderConstant.ORDER_JOIN_STATUS_PASSENGER_ABOARD: {
                return crosstownOrderProcessor.passengerGetOn(crosstownOrderParam);
            }
            //已到达 司机传600状态请求完成订单 当订单属于后付费时 需要先进入510确认费用界面
            case OrderConstant.ORDER_JOIN_STATUS_COMPLETED: {
                return crosstownOrderProcessor.arriveDestination(crosstownOrderParam);
            }
            //司机收现
            case OrderConstant.ORDER_JOIN_STATUS_DRIVER_PAY: {
                return crosstownOrderProcessor.makeDriverPay(crosstownOrderParam);
            }
            //发生账单给乘客支付
            case OrderConstant.ORDER_JOIN_STATUS_PASSENGER_PAY: {
                return crosstownOrderProcessor.makePassengerPay(crosstownOrderParam);
            }
            default:
                return ResponseData.buildErrorResponse(0, "订单状态无效");
        }
    }

    @Override
    public ResponseData<PageList<CrosstownOrderPoolInfoVo>> crosstownOrderPoolInfo(CrosstownOrderParam crosstownOrderParam) {
        PageBounds pageBounds = new PageBounds(crosstownOrderParam.getNowPage(), crosstownOrderParam.getPageSize());
        Map<String, Object> paraMap = new HashMap<>();
        paraMap.put("driverUuid", crosstownOrderParam.getDriverUuid());
        return ResponseData.buildSuccessResponse(orderMapper.getCrosstownOrderPoolInfo(paraMap, pageBounds));
    }

    @Override
    public ResponseData<Map<String, Object>> crosstownOrderPoolCount(CrosstownOrderParam crosstownOrderParam) {
        Map<String, Object> paraMap = new HashMap<>();
        paraMap.put("driverUuid", crosstownOrderParam.getDriverUuid());
        return ResponseData.buildSuccessResponse(MapUtils.build("orderCount", orderMapper.getCrosstownOrderPoolCount(paraMap)));
    }

    @Override
    public ResponseData<Map<String, Object>> mergeAssignVerify(MergeAssignParam mergeAssignParam) {
        Map<String, Object> paraMap = new HashMap<>();
        paraMap.put("orderUuidList", mergeAssignParam.getOrderUuidList());
        //当指派到主单时 将主单下的所有子单也一起返回
        if (StringUtils.isNotEmpty(mergeAssignParam.getMainOrderUuid())) {
            paraMap.put("mainOrderUuid", mergeAssignParam.getMainOrderUuid());
        }
        List<AdminChildOrderInfoVo> orderList = orderMapper.getChildOrderInfoById(paraMap);
        //时间间隔是否过大
        boolean timeIntevalTooLarge = false;
        //起终点是否距离过大
        boolean originDistanceTooLarge = false;
        boolean destDistanceTooLarge = false;

        for (int i = 0; i < orderList.size(); i++) {
            AdminChildOrderInfoVo IOrder = orderList.get(i);
            //两两对比起终点距离与出发时间差是否过大 暂定时间不超过一小时 距离不超过10公里
            for (int j = i + 1; j < orderList.size(); j++) {
                AdminChildOrderInfoVo JOrder = orderList.get(j);
                //已经得出超过限制条件结论时 不需要对剩下的订单再做校验
                if (!originDistanceTooLarge) {
                    //起点距离
                    log.info("起点距离{}", LocationUtils.getLineDistance(IOrder.getOriginLng(), IOrder.getOriginLat(), JOrder.getOriginLng(), JOrder.getOriginLat()));
                    if (LocationUtils.getLineDistance(IOrder.getOriginLng(), IOrder.getOriginLat(), JOrder.getOriginLng(), JOrder.getOriginLat()) > (10 * 1000)) {
                        originDistanceTooLarge = true;
                    }
                }
                if (!destDistanceTooLarge) {
                    //终点距离
                    log.info("终点距离{}", LocationUtils.getLineDistance(IOrder.getDestLng(), IOrder.getDestLat(), JOrder.getDestLng(), JOrder.getDestLat()));
                    if (LocationUtils.getLineDistance(IOrder.getDestLng(), IOrder.getDestLat(), JOrder.getDestLng(), JOrder.getDestLat()) > (10 * 1000)) {
                        destDistanceTooLarge = true;
                    }
                }
                if (!timeIntevalTooLarge) {
                    //出发时间间隔
                    log.info("出发时间间隔{}", Math.abs(JOrder.getDeparTime().getTime() - IOrder.getDeparTime().getTime()));
                    if ((Math.abs(JOrder.getDeparTime().getTime() - IOrder.getDeparTime().getTime()) > (60 * 60 * 1000))) {
                        timeIntevalTooLarge = true;
                    }
                }
            }
        }
        Map<String, Object> resultMap = new HashMap<>();
        //起终点或者出发时间间隔过大 需要提醒
        if (originDistanceTooLarge || destDistanceTooLarge || timeIntevalTooLarge) {
            StringBuilder warnMsg = new StringBuilder();
            if (originDistanceTooLarge) {
                warnMsg.append("、起点");
            }
            if (destDistanceTooLarge) {
                warnMsg.append("、终点");
            }
            if (warnMsg.length() > 0) {
                warnMsg.append("距离超过10公里");
            }
            if (timeIntevalTooLarge) {
                warnMsg.append("，出发时间间隔超过一小时");
            }
            resultMap.put("verifyState", false);
            resultMap.put("errorMsg", "订单" + warnMsg.substring(1) + "，请确认是否继续合并派单操作？");
            return ResponseData.buildSuccessResponse(resultMap);
        }
        resultMap.put("verifyState", true);
        return ResponseData.buildSuccessResponse(resultMap);
    }

    @Override
    public ResponseData<List<OrderDto>> queryRefundList(Map<String, Object> params) {
        return ResponseData.buildSuccessResponse(orderMapper.queryRefundList(params));
    }

    @Override
    public ResponseData<Boolean> crosstownEditOrderInfo(AdminOrderEditParam orderEditParam) {
        List<OrderDetailDto> detailList = orderDetailMapper.list(MapUtils.build("orderUuid", orderEditParam.getOrderUuid()));
        if (CollectionUtils.isEmpty(detailList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单详情失败");
        }
        List<OrderDto> orderList = orderMapper.list(MapUtils.build("uuid", orderEditParam.getOrderUuid()));
        if (CollectionUtils.isEmpty(orderList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单信息失败");
        }
        OrderDetailDto curOrderDetailDto = detailList.get(0);
        OrderDto curOrderDto = orderList.get(0);
        if (curOrderDto.getCloseStatus() == ORDER_CLOSE_STATUS_CLOSED) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单已被关闭，无法修改订单信息");
        }
        if (curOrderDto.getJoinStatus() >= ORDER_JOIN_STATUS_WAIT_START) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单已被指派，无法修改订单信息");
        }
        OrderDto editOrderDto = new OrderDto();
        OrderDetailDto editOrderDetailDto = new OrderDetailDto();
        List<SysWayDto> wayList = sysWayService.findWayInfoDetail(MapUtils.build("wayUuid", curOrderDto.getWayUuid())).getData();
        if (CollectionUtils.isEmpty(wayList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取线路信息失败");
        }
        SysWayDto sysWayDto = wayList.get(0);

        //锁订单
        if (!redisLock.uniqueLock(ASSIGN_ORDER_LOCK + orderEditParam.getOrderUuid())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单状态已发生改变，请刷新");
        }

        //日志保存
        List<SysBusinessOperateLogDto> saveLog = new ArrayList<>();
        //是否需要重新计算费用(乘客人数与出发时间变更时 需要重新估价)
        boolean isReCalcuFare = false;
        //修改内容
        StringBuilder editContent = new StringBuilder();

        //乘客人数判断
        if (!curOrderDetailDto.getActualPasNum().equals(orderEditParam.getPassengerNum())) {
            isReCalcuFare = true;
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "passengerNum"));
            editOrderDetailDto.setActualPasNum(orderEditParam.getPassengerNum());
            editOrderDetailDto.setAdultNum(orderEditParam.getPassengerNum());
            editOrderDto.setSeatNum(orderEditParam.getPassengerNum());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            editOrderDto.setUuid(curOrderDto.getUuid());
            editContent.append(",").append("乘客人数").append(curOrderDetailDto.getActualPasNum()).append("-->").append(orderEditParam.getPassengerNum());
        }
        //出发时间判断
        if (curOrderDetailDto.getDeparTime().getTime() != orderEditParam.getDeparTime().getTime()) {
            isReCalcuFare = true;
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "deparTime"));
            editOrderDetailDto.setDeparTime(orderEditParam.getDeparTime());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            editContent.append(",").append("出发时间").append(sdf.format(curOrderDetailDto.getDeparTime())).append("-->").append(sdf.format(orderEditParam.getDeparTime()));
        }
        //出发地址判断
        if (!(curOrderDetailDto.getOriginLat() + "," + curOrderDetailDto.getOriginLng()).equals(orderEditParam.getOriginLat() + "," + orderEditParam.getOriginLng())) {
            if (!OrderAssignHelper.joinWayMatch(orderEditParam.getAppid(), orderEditParam.getOriginLng(), orderEditParam.getOriginLat(),
                    sysWayDto.getOriginType(), sysWayDto.getOriginIncludeAreas(), sysWayDto.getOriginCityName(),
                    sysWayDto.getOriginLng(), sysWayDto.getOriginLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "起点坐标不在线路起点服务范围内");
            }
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "originAddress"));
            //设置出发地相关信息
            editOrderDetailDto.setOriginLng(orderEditParam.getOriginLng());
            editOrderDetailDto.setOriginLat(orderEditParam.getOriginLat());
            editOrderDetailDto.setOriginAddress(orderEditParam.getOriginAddress());
            editOrderDetailDto.setOriginDetailAddress(orderEditParam.getOriginDetailAddress());
            editOrderDetailDto.setOriginCity(orderEditParam.getOriginCity());
            editOrderDetailDto.setOriginAreaCode(orderEditParam.getOriginAreaCode());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            editOrderDetailDto.setOriginCityUuid(sysCityService.getCityUuidByName(orderEditParam.getOriginCity()).getData());
            editContent.append(",").append("出发地").append(curOrderDetailDto.getOriginDetailAddress()).append("-->").append(orderEditParam.getOriginDetailAddress());
        }
        //目的地址判断
        if (!(curOrderDetailDto.getDestLat() + "," + curOrderDetailDto.getDestLng()).equals(orderEditParam.getDestLat() + "," + orderEditParam.getDestLng())) {
            if (!OrderAssignHelper.joinWayMatch(orderEditParam.getAppid(), orderEditParam.getDestLng(), orderEditParam.getDestLat(),
                    sysWayDto.getDestType(), sysWayDto.getDestIncludeAreas(), sysWayDto.getDestCityName(),
                    sysWayDto.getDestLng(), sysWayDto.getDestLat())) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "终点坐标不在线路终点服务范围内");
            }
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "destAddress"));
            //设置目的地相关信息
            editOrderDetailDto.setDestLng(orderEditParam.getDestLng());
            editOrderDetailDto.setDestLat(orderEditParam.getDestLat());
            editOrderDetailDto.setDestAddress(orderEditParam.getDestAddress());
            editOrderDetailDto.setDestDetailAddress(orderEditParam.getDestDetailAddress());
            editOrderDetailDto.setDestCity(orderEditParam.getDestCity());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            editOrderDetailDto.setDestCityUuid(sysCityService.getCityUuidByName(orderEditParam.getDestCity()).getData());
            editContent.append(",").append("目的地").append(curOrderDetailDto.getDestDetailAddress()).append("-->").append(orderEditParam.getDestDetailAddress());
        }
        //备注更改
        if (!StringUtils.equals(orderEditParam.getRemark(), curOrderDetailDto.getRemark())) {
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "orderRemark"));
            editOrderDetailDto.setRemark(orderEditParam.getRemark());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            String curRemark = StringUtils.isEmpty(curOrderDetailDto.getRemark()) ? "无备注" : curOrderDetailDto.getRemark();
            editContent.append(",").append("备注更新").append(curRemark).append("-->").append(orderEditParam.getRemark());
        }
        //需要重新计算价格
        if (isReCalcuFare) {
            log.info("后台修改订单{}重新计算价格", curOrderDto.getUuid());
            OrderEvaluateParam orderEvaluateParam = new OrderEvaluateParam();
            BeanUtils.copyProperties(orderEditParam, orderEvaluateParam);
            log.info("后台修改订单" + orderEvaluateParam.getOriginLng() + "," + orderEvaluateParam.getOriginLat() + ";" + orderEvaluateParam.getDestLng() + "," + orderEvaluateParam.getDestLat() +
                    ";" + orderEvaluateParam.getAdultNum() + ";" + orderEvaluateParam.getCarModelUuid() + ";" + orderEvaluateParam.getDeparTime());
            orderEvaluateParam.setTypeJoin(curOrderDto.getTypeJoin());
            orderEvaluateParam.setOrderDemand(curOrderDto.getOrderDemand());
            orderEvaluateParam.setCarModelUuid(curOrderDto.getCarModelUuid());
            orderEvaluateParam.setOriginUuid(sysWayDto.getOriginSiteUuid());
            orderEvaluateParam.setDestUuid(sysWayDto.getDestSiteUuid());
            orderEvaluateParam.setAdultNum(orderEditParam.getPassengerNum());
            ResponseData<ApiJoinValuationVo> joinValuation = orderFareService.joinValuation(orderEvaluateParam);
            if (joinValuation.isSuccess()) {
                ApiJoinValuationVo joinValuationVo = joinValuation.getData();
                OrderFareDto orderFareDto = new OrderFareDto();
                double totalFare = ParamUtil.defaultIfNull(joinValuationVo.getTotalFare(), 0D);
                BigDecimal orderFare = BigDecimal.valueOf(ParamUtil.defaultIfNull(joinValuationVo.getOrderFare(), 0D));
                orderFareDto.setOriginRaisePrice(joinValuationVo.getOriginRaisePrice());
                orderFareDto.setDestRaisePrice(joinValuationVo.getDestRaisePrice());
                orderFareDto.setNightRaisePrice(joinValuationVo.getNightRaisePrice());

                orderFareDto.setTotalFare(totalFare);
                orderFareDto.setOrderFare(orderFare);
                orderFareDto.setLatestOrderFare(BigDecimal.valueOf(totalFare));

                orderFareDto.setOrderUuid(curOrderDto.getUuid());
                orderFareMapper.edit(orderFareDto);
            }
        }
        //保存日志
        if (saveLog.size() > 0) {
            sysBusinessOperateLogService.addBatch(saveLog);
        }
        if (editOrderDto.getUuid() != null) {
            orderMapper.edit(editOrderDto);
        }
        if (editOrderDetailDto.getOrderUuid() != null) {
            orderDetailMapper.edit(editOrderDetailDto);
        }
        if (editContent.length() > 0) {
            StringBuilder sBuilder = new StringBuilder().append("订单信息已被客服修改（").append(editContent.toString()
                    .substring(1)).append("），请合理安排您的乘车时间并保持电话畅通");
            // 推送乘客
            Map<String, Object> extraMap = MapUtils.build(4);
            extraMap.put("report", "您的订单信息已由客服修改，可进入订单查看详情");
            extraMap.put("typeModule", curOrderDto.getTypeModule());
            pushOrder2Pas(curOrderDto.getPassengerUuid(), curOrderDto.getUuid(), curOrderDto.getAppid(), null,
                    sBuilder.toString(), ORDER_ADMIN_EDIT_INFO, extraMap);
        }
        return ResponseData.buildSuccessResponse("修改成功", true);
    }

    @Override
    public ResponseData<Boolean> editAssignOrder(AdminOrderEditParam orderEditParam) {
        List<OrderDetailDto> detailList = orderDetailMapper.list(MapUtils.build("orderUuid", orderEditParam.getOrderUuid()));
        if (CollectionUtils.isEmpty(detailList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单详情失败");
        }
        List<OrderDto> orderList = orderMapper.list(MapUtils.build("uuid", orderEditParam.getOrderUuid()));
        if (CollectionUtils.isEmpty(orderList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单信息失败");
        }
        OrderDetailDto curOrderDetailDto = detailList.get(0);
        OrderDto curOrderDto = orderList.get(0);
        if (curOrderDto.getCloseStatus() == OrderConstant.ORDER_CLOSE_STATUS_CLOSED) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单已被关闭，无法修改订单信息");
        }
        if (curOrderDto.getJoinStatus() >= OrderConstant.ORDER_JOIN_STATUS_DRIVER_DEPARTURE) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "行程已经开始，无法修改订单信息");
        }
        OrderDto editOrderDto = new OrderDto();
        OrderDetailDto editOrderDetailDto = new OrderDetailDto();
        List<SysWayDto> wayList = sysWayService.findWayInfoDetail(MapUtils.build("wayUuid", curOrderDto.getWayUuid())).getData();
        if (CollectionUtils.isEmpty(wayList)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取线路信息失败");
        }
        SysWayDto sysWayDto = wayList.get(0);

        //锁订单
        if (!redisLock.uniqueLock(OrderAssignServiceImpl.ASSIGN_ORDER_LOCK + orderEditParam.getOrderUuid())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单状态已发生改变，请刷新");
        }
        OrderDetailDto mainOrderDetail = orderDetailMapper.list(MapUtils.build("orderUuid", curOrderDto.getMainOrderUuid())).get(0);
        OrderDetailDto editMainOrderDetail = new OrderDetailDto();
        OrderDto editMainOrderDto = new OrderDto();

        //日志保存
        List<SysBusinessOperateLogDto> saveLog = new ArrayList<>();
        //是否需要重新计算费用(乘客人数与出发时间变更时 需要重新估价)
        boolean isReCalcuFare = false;
        //修改内容
        StringBuilder editContent = new StringBuilder();

        //乘客人数判断
        if (!curOrderDetailDto.getActualPasNum().equals(orderEditParam.getPassengerNum())) {

            //拼车锁
            Integer actualNum = orderEditParam.getPassengerNum() - curOrderDetailDto.getActualPasNum();
            //人数改大时
            if (actualNum > 0) {
                String lockDriverKey = ASSIGN_DRIVER_LOCK + "usrCar" + curOrderDto.getActualDriverUuid() + curOrderDto.getMainOrderUuid();
                Long needNum = redisStringCacheService.incr(lockDriverKey);
                redisStringCacheService.expire(lockDriverKey, 2, TimeUnit.SECONDS);
                log.info("拼车订单key{} needNum{}", lockDriverKey, needNum);
                //司机有订单时 多个司机同时通过校验 判断订单数是否超过司机座位
                //若乘客所需的座位数大于1时 需要算上实际需要的座位数
                needNum = actualNum > 1 ? (needNum - 1 + actualNum) : needNum;
                if (needNum > mainOrderDetail.getResNum()) {
                    log.info("拼车订单{}被锁定，司机座位不足，无法派单needNum{}", curOrderDto.getUuid(), needNum);
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "司机座位不足");
                }
            }

            isReCalcuFare = true;
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "passengerNum"));
            editOrderDetailDto.setActualPasNum(orderEditParam.getPassengerNum());
            editOrderDetailDto.setAdultNum(orderEditParam.getPassengerNum());
            editOrderDto.setSeatNum(orderEditParam.getPassengerNum());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            editOrderDto.setUuid(curOrderDto.getUuid());

            OrderDto mainOrderDto = orderMapper.list(MapUtils.build("uuid", curOrderDto.getMainOrderUuid())).get(0);
            editMainOrderDto.setUuid(mainOrderDto.getUuid());
            editMainOrderDto.setSeatNum(mainOrderDto.getSeatNum() + actualNum);
            editMainOrderDetail.setActualPasNum(mainOrderDetail.getActualPasNum() + actualNum);
            editMainOrderDetail.setAdultNum(mainOrderDetail.getAdultNum() + actualNum);
            editMainOrderDetail.setResNum(mainOrderDetail.getResNum() - actualNum);
            editMainOrderDetail.setOrderUuid(mainOrderDetail.getOrderUuid());
            editContent.append(",").append("乘客人数").append(curOrderDetailDto.getActualPasNum()).append("-->").append(orderEditParam.getPassengerNum());
        }

        //备注更改
        if (!StringUtils.equals(orderEditParam.getRemark(), curOrderDetailDto.getRemark())) {
            saveLog.add(OrderHelper.orderOperateBuild(orderEditParam, curOrderDetailDto, "orderRemark"));
            editOrderDetailDto.setRemark(orderEditParam.getRemark());
            editOrderDetailDto.setOrderUuid(curOrderDto.getUuid());
            String curRemark = StringUtils.isEmpty(curOrderDetailDto.getRemark()) ? "无备注" : curOrderDetailDto.getRemark();
            editContent.append(",").append("备注更新").append(curRemark).append("-->").append(orderEditParam.getRemark());
        }
        //需要重新计算价格
        if (isReCalcuFare) {
            log.info("后台修改订单{}重新计算价格", curOrderDto.getUuid());
            OrderEvaluateParam orderEvaluateParam = new OrderEvaluateParam();
            BeanUtils.copyProperties(orderEditParam, orderEvaluateParam);
            log.info("后台修改订单" + orderEvaluateParam.getOriginLng() + "," + orderEvaluateParam.getOriginLat() + ";" + orderEvaluateParam.getDestLng() + "," + orderEvaluateParam.getDestLat() +
                    ";" + orderEvaluateParam.getAdultNum() + ";" + orderEvaluateParam.getCarModelUuid() + ";" + orderEvaluateParam.getDeparTime());
            orderEvaluateParam.setTypeJoin(curOrderDto.getTypeJoin());
            orderEvaluateParam.setOrderDemand(curOrderDto.getOrderDemand());
            orderEvaluateParam.setCarModelUuid(curOrderDto.getCarModelUuid());
            orderEvaluateParam.setOriginUuid(sysWayDto.getOriginSiteUuid());
            orderEvaluateParam.setDestUuid(sysWayDto.getDestSiteUuid());
            orderEvaluateParam.setAdultNum(orderEditParam.getPassengerNum());
            ResponseData<ApiJoinValuationVo> fareRS = orderFareService.joinValuation(orderEvaluateParam);
            if (fareRS.isSuccess()) {
                ApiJoinValuationVo fareRSData = fareRS.getData();
                OrderFareDto orderFareDto = new OrderFareDto();
                Double totalFare = null != fareRSData.getTotalFare() ? fareRSData.getTotalFare() : 0d;
                BigDecimal orderFare = null != fareRSData.getOrderFare() ? BigDecimal.valueOf(fareRSData.getOrderFare()) : BigDecimal.ZERO;
                orderFareDto.setOriginRaisePrice(fareRSData.getOriginRaisePrice());
                orderFareDto.setDestRaisePrice(fareRSData.getDestRaisePrice());
                orderFareDto.setNightRaisePrice(fareRSData.getNightRaisePrice());

                orderFareDto.setTotalFare(totalFare);
                orderFareDto.setOrderFare(orderFare);
                orderFareDto.setLatestOrderFare(BigDecimal.valueOf(totalFare));

                orderFareDto.setOrderUuid(curOrderDto.getUuid());
                orderFareMapper.edit(orderFareDto);
            }
        }
        //保存日志
        if (saveLog.size() > 0) {
            try {
                sysBusinessOperateLogService.addBatch(saveLog);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (editOrderDto.getUuid() != null) {
            orderMapper.edit(editOrderDto);
        }
        if (editOrderDetailDto.getOrderUuid() != null) {
            orderDetailMapper.edit(editOrderDetailDto);
        }
        if (editMainOrderDetail.getOrderUuid() != null) {
            orderMapper.edit(editMainOrderDto);
            orderDetailMapper.edit(editMainOrderDetail);
        }
        if (editContent.length() > 0) {
            // 推送乘客
            Map<String, Object> data = MapUtils.build();
            data.put("orderUuid", curOrderDto.getUuid());
            StringBuilder pushContent = new StringBuilder();
            pushContent.append("订单信息已被客服修改（").append(editContent.toString().substring(1)).append("），请合理安排您的乘车时间并保持电话畅通");
            data.put("content", pushContent.toString());
            data.put("report", "您的订单信息已由客服修改，可进入订单查看详情");
            data.put("orderType", curOrderDto.getTypeModule());
            pushService.sendMessage(curOrderDto.getPassengerUuid(), PushContent.newInstance4Pas(curOrderDto.getAppid(), PushContent.ORDER_ADMIN_EDIT_INFO, data));
        }
        return ResponseData.buildSuccessResponse("修改成功", true);
    }

    @Override
    public ResponseData<List<CrosstownMergeAssignInfoVo>> crosstownAssignInfo(MergeAssignParam mergeAssignParam) {
        List<CrosstownMergeAssignInfoVo> list = orderMapper.crosstownMergeAssignInfo(mergeAssignParam.getOrderUuidList());
        if (CollectionUtils.isEmpty(list)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取订单信息失败");
        }
        int total = list.size();
        int sequenceNumber = 0;
        //设置订单与司机距离
        for (CrosstownMergeAssignInfoVo orderInfo : list) {
            orderInfo.setSequenceNumber(sequenceNumber++);
            orderInfo.setTotal(total);
            DriverPoint driverPoint = locationService.findDriverPoint(mergeAssignParam.getDriverUuid(), mergeAssignParam.getAppid()).getData();
            if (driverPoint != null) {
                DrivingNearestVo drivingNearest = distanceService.getDrivingNearest(orderInfo.getOriginLng(),
                        orderInfo.getOriginLat(), String.valueOf(driverPoint.getCoordinate().getLng()),
                        String.valueOf(driverPoint.getCoordinate().getLat())).getData();
                //单位
                String unit;
                Double distance = drivingNearest.getDistance();
                if (distance > 1000) {
                    distance = distance / 1000;
                    unit = "公里";
                } else {
                    unit = "米";
                }
                orderInfo.setDistance(distance + unit);
            }
        }
        return ResponseData.buildSuccessResponse(list);
    }

    @Override
    public ResponseData<Boolean> mergeAssignPreHandle(MergeAssignParam mergeAssignParam) {
        List<AdminChildOrderInfoVo> orderList = orderMapper.getChildOrderInfoById(MapUtils.build("orderUuidList", mergeAssignParam.getOrderUuidList()));
        //循环校验订单类型是否一致 并对订单两两之间的距离做比较
        Integer orderDemand = null;
        Integer typeJoin = null;
        String wayUuid = null;
        String carModelUuid = null;
        //二人快车数量
        Integer twoPersonsNum = 0;
        for (int i = 0; i < orderList.size(); i++) {
            AdminChildOrderInfoVo iOrder = orderList.get(i);
            if (iOrder.getTypeJoin() == CommonConstant.ORDER_TYPE_JOIN_TWO_PERSONS) {
                twoPersonsNum += 1;
            }
            //优先筛选是否有包车单的存在 包车订单无法合并
            if (iOrder.getTypeJoin() == CommonConstant.ORDER_TYPE_JOIN_CHARTERED) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "包车订单请在订单卡片列表单独派单！");
            }
            //取出集合中的第一个订单信息 对后续订单进行对比
            if (i == 0) {
                orderDemand = iOrder.getOrderDemand();
                typeJoin = iOrder.getTypeJoin();
                wayUuid = iOrder.getWayUuid();
                //非跨城小件时 取出车型
                if (iOrder.getTypeModule() == CommonConstant.BUSINESS_TYPE_POOL) {
                    carModelUuid = iOrder.getCarModelUuid();
                }
            }
            //从第二个订单开始 对比是否存在订单类型不一致的问题
            if (i > 0) {
                //线路是否相同
                if (!wayUuid.equals(iOrder.getWayUuid())) {
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单不属于相同线路，无法合并派单！");
                }
                //存在前几个订单为跨城小件 未赋值车型 则在后面订单中再次取出
                if (StringUtils.isEmpty(carModelUuid)) {
                    carModelUuid = iOrder.getCarModelUuid();
                }
                //非小件需要对比车型是否相同
                if (iOrder.getTypeModule() == CommonConstant.BUSINESS_TYPE_POOL && !carModelUuid.equals(iOrder.getCarModelUuid())) {
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "订单车型需求不一致，无法合并派单！");
                }
                //是否都是普通订单或者机场专线
                if (!orderDemand.equals(iOrder.getOrderDemand())) {
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "普通订单无法与机场专线合并派单！");
                }
                //判断订单类型是否一致 经济拼车单与跨城小件不允许与二人快车单匹配
                if ((typeJoin == CommonConstant.ORDER_TYPE_JOIN_TWO_PERSONS || iOrder.getTypeJoin() == CommonConstant.ORDER_TYPE_JOIN_TWO_PERSONS)
                        && !typeJoin.equals(iOrder.getTypeJoin())) {
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "二人快车无法与其他类型订单合并派单！");
                }
            }
        }
        if (twoPersonsNum > 2) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "二人快车订单数量超过两单，无法合并派单");
        }
        return ResponseData.buildSuccessResponse("校验通过", true);
    }

    @Override
    public ResponseData<ApiCrosstownOrderInfoVo> getCrosstownOrderInfo(String orderUuid) {
        ApiCrosstownOrderInfoVo orderInfoVo = orderMapper.getCrosstownOrderInfo(orderUuid);
        if (orderInfoVo == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "未获取到订单信息");
        }
        //增加是否超过24小时
        orderInfoVo.setOverTime(0);
        if (orderInfoVo.getDeparTime() != null && DateUtils.compareByDay(new Date(), orderInfoVo.getDeparTime(), 1)) {
            orderInfoVo.setOverTime(1);
        }
        //获取司机所有成功单数
        List<OrderDto> orderDtos = orderMapper.driverAccomplishOrder(orderInfoVo.getDriverUuid());
        if (orderDtos.size() != 0) {
            orderInfoVo.setDriverOrderCount(orderDtos.size());
        }

        String[] parcelInfoName = orderInfoVo.getParcelInfoName().split(",");
        orderInfoVo.setParcelTypeName(parcelInfoName[0]);
        orderInfoVo.setParcelWeightName(parcelInfoName[1]);
        orderInfoVo.setParcelVolumeName(parcelInfoName[2]);
        orderInfoVo.setParcelPhoto(orderInfoVo.getParcelPhoto());

        //待支付状态时 支付获取优惠券
        if (orderInfoVo.getJoinStatus() == ORDER_JOIN_STATUS_INIT
                && orderInfoVo.getCloseStatus() == ORDER_CLOSE_STATUS_NORMAL) {
            List<PassengerCouponDto> passengerCouponDtoList = passengerCouponService.findJoinMinCoupon(
                    orderInfoVo.getPassengerUuid(), orderInfoVo.getTypeModule(),
                    orderInfoVo.getTotalFare(), orderInfoVo.getOriginCity()).getData();
            if (passengerCouponDtoList != null && passengerCouponDtoList.size() > 0) {
                PassengerCouponDto couponDto = passengerCouponDtoList.get(0);
                orderInfoVo.setCouponUuid(couponDto.getUuid());
                orderInfoVo.setCouponFare(couponDto.getMoney());
            }
        }
        //订单处于已派单未完成状态时 返回当前激活订单与拼友信息
        if (orderInfoVo.getJoinStatus() >= ORDER_JOIN_STATUS_WAIT_START
                && orderInfoVo.getJoinStatus() < ORDER_JOIN_STATUS_COMPLETED) {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("mainOrderUuid", orderInfoVo.getMainOrderUuid());
            List<AllPassengerOrderVo> otherOrderInfoList = orderMapper.allPassengerOrderInfo(MapUtils.build("mainOrderUuid", orderInfoVo.getMainOrderUuid()));

            //取出当前订单 并处理当前激活订单
            if (otherOrderInfoList != null && otherOrderInfoList.size() > 0) {
                //当前激活订单
                for (AllPassengerOrderVo orderVo : otherOrderInfoList) {
                    //顺位第一个待接驾、待上车订单或者行程中订单为激活订单
                    if (orderVo.getJoinStatus() == ORDER_JOIN_STATUS_DRIVER_DEPARTURE
                            || orderVo.getJoinStatus() == ORDER_JOIN_STATUS_STARTED
                            || orderVo.getJoinStatus() == ORDER_JOIN_STATUS_ARRIVE_POINT) {
                        orderInfoVo.setActivateOrderUuid(orderVo.getOrderUuid());
                        orderInfoVo.setActivatePassengerName(orderVo.getPassengerName());
                        orderInfoVo.setActivateOrderModule(orderVo.getTypeModule());
                        break;
                    }
                }
                orderInfoVo.setAllPassengerOrderInfo(otherOrderInfoList);
            }
        } else if (orderInfoVo.getJoinStatus() > ORDER_JOIN_STATUS_STARTED) {
            //跨城订单已完成时 加载定位点
            JsonOrderDetailVo jsonOrderDetailVo = new JsonOrderDetailVo();
            jsonOrderDetailVo.setOrderUuid(orderUuid);
            jsonOrderDetailVo.setMainOrderUuid(orderInfoVo.getMainOrderUuid());
            jsonOrderDetailVo.setAppid(orderInfoVo.getAppid());
            orderInfoVo.setTracePoints(getCrosstownTracePoint(jsonOrderDetailVo));
        }
        return ResponseData.buildSuccessResponse(orderInfoVo);
    }

    /**
     * 获取进行中订单
     *
     * @param driverUuid
     * @return
     */
    @Override
    public ResponseData<Map<String, Object>> getCrosstownUnderwayOrder(String driverUuid) {
        String orderUuid = orderMapper.getCrosstownUnderwayOrder(driverUuid);
        return ResponseData.buildSuccessResponse(MapUtils.build("mainOrderUuid", ParamUtil.defaultIfNull(orderUuid, "")));
    }

    /**
     * 获取首页订单信息
     *
     * @param params
     * @return
     */
    @Override
    public ResponseData<List<CrosstownHomeOrderInfoVo>> getCrosstownHomeOrderInfo(Map<String, Object> params) {
        List<CrosstownHomeOrderInfoVo> result = orderMapper.getCrosstownHomeOrderInfo(params);
        if (CollectionUtils.isEmpty(result)) {
            result = new ArrayList<>();
        }
        return ResponseData.buildSuccessResponse(result);
    }

    @Override
    public ResponseData<List<CrosstownOrderTaskInfoVo>> taskList(CrosstownOrderParam crosstownOrderParam) {
        List<CrosstownOrderTaskInfoVo> list = orderMapper.taskList(crosstownOrderParam.getMainOrderUuid());
        return ResponseData.buildSuccessResponse(list);
    }
}
